mirror of
https://github.com/tinygrad/tinygrad.git
synced 2026-08-15 20:58:28 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8b6182355a |
@@ -1,4 +0,0 @@
|
||||
# 2 space indentation
|
||||
[*.py]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
@@ -1,8 +0,0 @@
|
||||
[flake8] # https://flake8.pycqa.org/en/6.0.0/user/options.html#cmdoption-flake8-select
|
||||
filename =
|
||||
*/tinygrad/*.py,
|
||||
*/test/*.py
|
||||
select=F,W6,E71,E72,E112,E113,E124,E203,E272,E303,E304,E502,E702,E703,E731,W191
|
||||
indent-size=2
|
||||
per-file-ignores =
|
||||
test/*: F401, F403, F405, F541, E722, E731, F811, F821, F841
|
||||
@@ -1,100 +0,0 @@
|
||||
name: Benchmarks
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- update_benchmark
|
||||
|
||||
jobs:
|
||||
testmacbenchmark:
|
||||
name: Mac Benchmark
|
||||
runs-on: [self-hosted, macOS]
|
||||
if: github.repository_owner == 'tinygrad'
|
||||
env:
|
||||
PYTHONPATH: .
|
||||
steps:
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@v3
|
||||
- name: Run model inference benchmark
|
||||
run: python3 test/external/external_model_benchmark.py
|
||||
- name: Test speed vs torch
|
||||
run: BIG=2 MPS=1 python3 test/test_speed_v_torch.py | tee torch_speed.txt
|
||||
- name: Run Tensor Core GEMM
|
||||
run: DEBUG=2 python3 extra/gemm/simple_matmul.py | tee matmul.txt
|
||||
- name: Run Stable Diffusion
|
||||
run: |
|
||||
ln -s ~/tinygrad/weights/sd-v1-4.ckpt weights/sd-v1-4.ckpt
|
||||
ln -s ~/tinygrad/weights/bpe_simple_vocab_16e6.txt.gz weights/bpe_simple_vocab_16e6.txt.gz
|
||||
time python3 examples/stable_diffusion.py --noshow
|
||||
- name: Run LLaMA
|
||||
run: |
|
||||
ln -s ~/tinygrad/weights/LLaMA weights/LLaMA
|
||||
python3 examples/llama.py --prompt "Hello." --count 10 --temperature 0 --timing | tee llama_unjitted.txt
|
||||
JIT=1 python3 examples/llama.py --prompt "Hello." --count 10 --temperature 0 --timing | tee llama_jitted.txt
|
||||
- name: Run GPT2
|
||||
run: |
|
||||
python3 examples/gpt2.py --prompt "Hello." --count 10 --temperature 0 --timing | tee gpt2_unjitted.txt
|
||||
JIT=1 python3 examples/gpt2.py --prompt "Hello." --count 10 --temperature 0 --timing | tee gpt2_jitted.txt
|
||||
- name: Run 10 CIFAR training steps
|
||||
run: |
|
||||
ln -s ~/tinygrad/extra/datasets/cifar-10-python.tar.gz extra/datasets/cifar-10-python.tar.gz
|
||||
STEPS=10 python3 examples/hlb_cifar10.py | tee train_cifar.txt
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Speed (Mac)
|
||||
path: |
|
||||
onnx_inference_speed.csv
|
||||
torch_speed.txt
|
||||
train_cifar.txt
|
||||
llama_unjitted.txt
|
||||
llama_jitted.txt
|
||||
gpt2_unjitted.txt
|
||||
gpt2_jitted.txt
|
||||
matmul.txt
|
||||
|
||||
testamdbenchmark:
|
||||
name: AMD Benchmark
|
||||
runs-on: [self-hosted, Linux]
|
||||
if: github.repository_owner == 'tinygrad'
|
||||
env:
|
||||
PYTHONPATH: .
|
||||
steps:
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@v3
|
||||
- name: Run model inference benchmark
|
||||
run: python3 test/external/external_model_benchmark.py
|
||||
- name: Test speed vs torch
|
||||
run: BIG=2 TORCHCUDA=1 python3 test/test_speed_v_torch.py | tee torch_speed.txt
|
||||
- name: Run Tensor Core GEMM
|
||||
run: HIP=1 HALF=1 DEBUG=2 python3 extra/gemm/simple_matmul.py | tee matmul.txt
|
||||
- name: Run Stable Diffusion
|
||||
run: |
|
||||
ln -s ~/tinygrad/weights/sd-v1-4.ckpt weights/sd-v1-4.ckpt
|
||||
ln -s ~/tinygrad/weights/bpe_simple_vocab_16e6.txt.gz weights/bpe_simple_vocab_16e6.txt.gz
|
||||
time DEBUG=1 python3 examples/stable_diffusion.py --noshow
|
||||
- name: Run LLaMA
|
||||
run: |
|
||||
ln -s ~/tinygrad/weights/LLaMA weights/LLaMA
|
||||
python3 examples/llama.py --prompt "Hello." --count 10 --temperature 0 --timing | tee llama_unjitted.txt
|
||||
JIT=1 python3 examples/llama.py --prompt "Hello." --count 10 --temperature 0 --timing | tee llama_jitted.txt
|
||||
- name: Run GPT2
|
||||
run: |
|
||||
python3 examples/gpt2.py --prompt "Hello." --count 10 --temperature 0 --timing | tee gpt2_unjitted.txt
|
||||
JIT=1 python3 examples/gpt2.py --prompt "Hello." --count 10 --temperature 0 --timing | tee gpt2_jitted.txt
|
||||
- name: Run 10 CIFAR training steps
|
||||
run: |
|
||||
ln -s ~/tinygrad/extra/datasets/cifar-10-python.tar.gz extra/datasets/cifar-10-python.tar.gz
|
||||
STEPS=10 python3 examples/hlb_cifar10.py | tee train_cifar.txt
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Speed (AMD)
|
||||
path: |
|
||||
onnx_inference_speed.csv
|
||||
torch_speed.txt
|
||||
train_cifar.txt
|
||||
llama_unjitted.txt
|
||||
llama_jitted.txt
|
||||
gpt2_unjitted.txt
|
||||
gpt2_jitted.txt
|
||||
matmul.txt
|
||||
@@ -1,31 +0,0 @@
|
||||
# This workflows will upload a Python Package using Twine when a release is created
|
||||
# For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries
|
||||
|
||||
name: Upload Python Package
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [created]
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install setuptools wheel twine
|
||||
- name: Build and publish
|
||||
env:
|
||||
TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}
|
||||
TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
|
||||
run: |
|
||||
python setup.py sdist bdist_wheel
|
||||
twine upload dist/*
|
||||
@@ -1,298 +0,0 @@
|
||||
name: Unit Tests
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
linter:
|
||||
name: Linters
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 20
|
||||
|
||||
steps:
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@v3
|
||||
- name: Set up Python 3.8
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: 3.8
|
||||
- name: Cache python packages
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ${{ env.Python3_ROOT_DIR }}/lib/python3.8/site-packages
|
||||
key: linting-packages-${{ hashFiles('*/setup.py') }}-3.8
|
||||
- name: Install dependencies
|
||||
run: pip install -e '.[linting,testing]' --extra-index-url https://download.pytorch.org/whl/cpu
|
||||
- name: Repo line count
|
||||
run: python sz.py
|
||||
- name: Lint with pylint
|
||||
run: python -m pylint --disable=all -e W0311 -e C0303 --jobs=0 --indent-string=' ' **/*.py
|
||||
- name: Lint with flake8
|
||||
run: python -m flake8 . --statistics -j4
|
||||
- name: Lint tinygrad with pylint
|
||||
run: python -m pylint tinygrad/
|
||||
- name: Run mypy
|
||||
run: python -m mypy tinygrad/ --ignore-missing-imports --check-untyped-defs --explicit-package-bases --warn-unreachable
|
||||
- name: Install SLOCCount
|
||||
run: sudo apt install sloccount
|
||||
- name: Check <5000 lines
|
||||
run: sloccount tinygrad test examples extra; if [ $(sloccount tinygrad | sed -n 's/.*Total Physical Source Lines of Code (SLOC)[ ]*= \([^ ]*\).*/\1/p' | tr -d ',') -gt 5000 ]; then exit 1; fi
|
||||
|
||||
testcpuimagenet:
|
||||
name: CPU and ImageNet to C Tests
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 20
|
||||
|
||||
steps:
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@v3
|
||||
- name: Set up Python 3.11
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: 3.11
|
||||
- name: Cache python packages
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ${{ env.Python3_ROOT_DIR }}/lib/python3.11/site-packages
|
||||
key: testing-packages-${{ hashFiles('*/setup.py') }}
|
||||
- name: Install Dependencies
|
||||
run: pip install -e '.[testing]' --extra-index-url https://download.pytorch.org/whl/cpu
|
||||
- name: Test Docs
|
||||
run: python docs/abstractions.py
|
||||
- name: Test Quickstart
|
||||
run: awk '/```python/{flag=1;next}/```/{flag=0}flag' docs/quickstart.md > quickstart.py && PYTHONPATH=. python quickstart.py
|
||||
- name: Run Pytest
|
||||
run: python -m pytest -n=auto test/ -k "not (test_efficientnet and models/test_train.py)"
|
||||
- name: Fuzz Test symbolic
|
||||
run: python test/external/fuzz_symbolic.py
|
||||
- name: Fuzz Test shapetracker
|
||||
run: PYTHONPATH="." python test/external/fuzz_shapetracker.py
|
||||
- name: Compile EfficientNet to C
|
||||
run: PYTHONPATH="." CLANG=1 python examples/compile_efficientnet.py > recognize.c
|
||||
- name: Compile C to native
|
||||
run: clang -O2 recognize.c -lm -o recognize
|
||||
- name: Test EfficientNet
|
||||
run: curl https://media.istockphoto.com/photos/hen-picture-id831791190 | ./recognize | grep hen
|
||||
|
||||
testtorch:
|
||||
name: Torch Tests
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 20
|
||||
|
||||
steps:
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@v3
|
||||
- name: Set up Python 3.11
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: 3.11
|
||||
- name: Cache python packages
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ${{ env.Python3_ROOT_DIR }}/lib/python3.11/site-packages
|
||||
key: testing-packages-${{ hashFiles('*/setup.py') }}
|
||||
- name: Install Dependencies
|
||||
run: pip install -e '.[testing]' --extra-index-url https://download.pytorch.org/whl/cpu
|
||||
- name: Run Pytest
|
||||
run: TORCH=1 python -m pytest -n=auto test/
|
||||
- name: Run ONNX
|
||||
run: TORCH=1 python -m pytest -n=auto test/external/external_test_onnx_backend.py --tb=no --disable-warnings || true
|
||||
|
||||
testopencl:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
task: [optimage, openpilot, multigpu]
|
||||
name: ${{ matrix.task=='optimage'&&'GPU OPT and IMAGE Tests'|| matrix.task=='openpilot'&&'openpilot (OpenCL) Tests'|| matrix.task=='multigpu'&&'MultiGPU Tests'}}
|
||||
runs-on: ubuntu-20.04
|
||||
timeout-minutes: 20
|
||||
|
||||
steps:
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@v3
|
||||
# - name: Find faster apt mirror
|
||||
# uses: vegardit/fast-apt-mirror.sh@v1
|
||||
- name: Install OpenCL
|
||||
#run: sudo apt install -y pocl-opencl-icd
|
||||
run: |
|
||||
wget -O- https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB | gpg --dearmor | sudo tee /usr/share/keyrings/oneapi-archive-keyring.gpg > /dev/null
|
||||
echo "deb [signed-by=/usr/share/keyrings/oneapi-archive-keyring.gpg] https://apt.repos.intel.com/oneapi all main" | sudo tee /etc/apt/sources.list.d/oneAPI.list
|
||||
sudo apt update
|
||||
sudo apt install -y --no-install-recommends intel-oneapi-runtime-compilers intel-oneapi-runtime-opencl
|
||||
- name: Set up Python 3.11
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: 3.11
|
||||
- name: Cache python packages
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ${{ env.Python3_ROOT_DIR }}/lib/python3.11/site-packages
|
||||
key: testing-packages-${{ hashFiles('*/setup.py') }}
|
||||
- name: Install Dependencies
|
||||
run: pip install -e '.[testing]' --extra-index-url https://download.pytorch.org/whl/cpu
|
||||
- if: ${{ matrix.task == 'optimage' }}
|
||||
name: Run Optimizer Test (OPT 2 and 3)
|
||||
run: |
|
||||
PYTHONPATH="." OPT=2 GPU=1 python -m pytest -n=auto test/external/external_test_opt.py
|
||||
PYTHONPATH="." OPT=3 GPU=1 python -m pytest -n=auto test/external/external_test_opt.py
|
||||
- if: ${{ matrix.task == 'optimage'}}
|
||||
name: Test GPU IMAGE ops
|
||||
run: |
|
||||
GPU=1 IMAGE=1 python -m pytest -n=auto test/test_ops.py
|
||||
FORWARD_ONLY=1 GPU=1 IMAGE=2 python -m pytest -n=auto test/test_ops.py
|
||||
- if: ${{ matrix.task == 'openpilot' }}
|
||||
name: Test openpilot model compile and size
|
||||
run: |
|
||||
DEBUG=2 ALLOWED_KERNEL_COUNT=209 FLOAT16=1 DEBUGCL=1 GPU=1 IMAGE=2 python openpilot/compile.py
|
||||
python -c 'import os; assert os.path.getsize("/tmp/output.thneed") < 100_000_000'
|
||||
- if: ${{ matrix.task == 'openpilot' }}
|
||||
name: Test openpilot model correctness (float32)
|
||||
run: DEBUGCL=1 GPU=1 IMAGE=2 python openpilot/compile.py
|
||||
- if: ${{ matrix.task == 'openpilot' }}
|
||||
name: Test tensor core ops
|
||||
run: GPU=1 TC=2 python -m pytest -n=auto test/test_ops.py
|
||||
- if: ${{ matrix.task == 'multigpu' }}
|
||||
name: Test multigpu
|
||||
run: |
|
||||
PYTHONPATH="." python test/external/dist/test_world.py
|
||||
PYTHONPATH="." python test/external/dist/test_collectives.py
|
||||
|
||||
testmetalwebgpu:
|
||||
name: Metal and WebGPU Tests
|
||||
runs-on: macos-13
|
||||
timeout-minutes: 20
|
||||
|
||||
steps:
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@v3
|
||||
- name: Set up Python 3.11
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: 3.11
|
||||
- name: Cache python packages
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ${{ env.Python3_ROOT_DIR }}/lib/python3.11/site-packages
|
||||
key: metal-webgpu-testing-packages-${{ hashFiles('*/setup.py') }}
|
||||
- name: Install Dependencies
|
||||
run: pip install -e '.[metal,webgpu,testing]' --extra-index-url https://download.pytorch.org/whl/cpu
|
||||
- name: Test LLaMA compile speed
|
||||
run: PYTHONPATH="." METAL=1 python test/external/external_test_speed_llama.py
|
||||
#- name: Run dtype test
|
||||
# run: DEBUG=4 METAL=1 python -m pytest -n=auto test/test_dtype.py
|
||||
# dtype test has issues on test_half_to_int8
|
||||
- name: Run metal ops test
|
||||
run: DEBUG=2 METAL=1 python -m pytest -n=auto test/test_ops.py
|
||||
- name: Run JIT test
|
||||
run: DEBUG=2 METAL=1 python -m pytest -n=auto test/test_jit.py
|
||||
- name: Run symbolic shapetracker test
|
||||
run: METAL=1 python -m pytest -n=auto test/test_symbolic_shapetracker.py test/test_symbolic_ops.py test/test_symbolic_jit.py
|
||||
- name: Check Device.DEFAULT
|
||||
run: WEBGPU=1 python -c "from tinygrad.ops import Device; assert Device.DEFAULT == 'WEBGPU', Device.DEFAULT"
|
||||
#- name: Run webgpu pytest
|
||||
# run: WEBGPU=1 WGPU_BACKEND_TYPE=Metal python -m pytest -n=auto --ignore test/models/ --ignore test/unit/test_example.py --ignore test/extra/test_lr_scheduler.py --ignore test/test_linearizer.py test/
|
||||
#- name: Build WEBGPU Efficientnet
|
||||
# run: WEBGPU=1 WGPU_BACKEND_TYPE=Metal python -m examples.compile_efficientnet
|
||||
|
||||
tests:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
backend: [llvm, clang, gpu, cuda, ptx]
|
||||
|
||||
name: Tests on (${{ matrix.backend }})
|
||||
runs-on: ${{ matrix.backend == 'gpu' && 'ubuntu-20.04' || 'ubuntu-latest' }}
|
||||
timeout-minutes: 20
|
||||
|
||||
steps:
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@v3
|
||||
- name: Set up Python 3.11
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: 3.11
|
||||
- name: Cache python packages
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ${{ env.Python3_ROOT_DIR }}/lib/python3.11/site-packages
|
||||
key: ${{ matrix.backend }}-packages-${{ hashFiles('*/setup.py') }}
|
||||
- name: Set env
|
||||
run: printf "${{ matrix.backend == 'llvm' && 'ENABLE_METHOD_CACHE=1\nLLVM=1' || matrix.backend == 'clang' && 'CLANG=1\nENABLED_METHOD_CACHE=1' || matrix.backend == 'gpu' && 'GPU=1' || matrix.backend == 'cuda' && 'FORWARD_ONLY=1\nJIT=1\nOPT=2\nCUDA=1\nCUDACPU=1\n' || matrix.backend == 'PTX' && 'FORWARD_ONLY=1\nJIT=1\nOPT=2\nCUDA=1\nCUDACPU=1\nPTX=1' }}" >> $GITHUB_ENV
|
||||
- name: Find faster apt mirror
|
||||
# uses: vegardit/fast-apt-mirror.sh@v1
|
||||
# - name: Install packages (gpu)
|
||||
if: matrix.backend == 'gpu'
|
||||
run: |
|
||||
wget -O- https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB | gpg --dearmor | sudo tee /usr/share/keyrings/oneapi-archive-keyring.gpg > /dev/null
|
||||
echo "deb [signed-by=/usr/share/keyrings/oneapi-archive-keyring.gpg] https://apt.repos.intel.com/oneapi all main" | sudo tee /etc/apt/sources.list.d/oneAPI.list
|
||||
sudo apt update -y
|
||||
sudo apt install -y --no-install-recommends intel-oneapi-runtime-compilers intel-oneapi-runtime-opencl
|
||||
- name: Install packages (cuda)
|
||||
if: matrix.backend == 'cuda' || matrix.backend == 'ptx'
|
||||
run: |
|
||||
sudo apt update -y
|
||||
sudo apt install -y --no-install-recommends git g++ cmake ninja-build llvm-15-dev zlib1g-dev libglew-dev flex bison libfl-dev libboost-thread-dev libboost-filesystem-dev nvidia-cuda-toolkit-gcc
|
||||
- name: Cache gpuocelot
|
||||
if: matrix.backend == 'cuda' || matrix.backend == 'ptx'
|
||||
id: cache-build
|
||||
uses: actions/cache@v3
|
||||
env:
|
||||
cache-name: cache-gpuocelot-build
|
||||
with:
|
||||
path: ${{ github.workspace }}/gpuocelot/ocelot
|
||||
key: ubuntu22.04-gpuocelot-19626fc00b6ee321638c3111074269c69050e091
|
||||
- name: Clone/compile gpuocelot
|
||||
if: (matrix.backend == 'cuda' || matrix.backend == 'ptx') && steps.cache-build.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
git clone --recurse-submodules https://github.com/gpuocelot/gpuocelot.git ${{ github.workspace }}/gpuocelot
|
||||
cd ${{ github.workspace }}/gpuocelot/ocelot
|
||||
git checkout 19626fc00b6ee321638c3111074269c69050e091
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -Wno-dev -G Ninja -DOCELOT_BUILD_TOOLS=OFF
|
||||
ninja
|
||||
- name: Install gpuocelot
|
||||
if: matrix.backend == 'cuda' || matrix.backend == 'ptx'
|
||||
run: |
|
||||
cd ${{ github.workspace }}/gpuocelot/ocelot/build
|
||||
sudo ninja install
|
||||
- name: Install dependencies
|
||||
run: pip install -e '.[testing${{matrix.backend=='llvm'&&',llvm'||matrix.backend=='cuda'&&',cuda'||matrix.backend=='ptx'&&',cuda'||''}}]' --extra-index-url https://download.pytorch.org/whl/cpu
|
||||
- name: Check Device.DEFAULT
|
||||
run: python -c "from tinygrad.ops import Device; assert Device.DEFAULT in ['LLVM','CLANG','CUDA','GPU'], Device.DEFAULT"
|
||||
- name: Run pytest (not cuda)
|
||||
if: matrix.backend!='cuda' && matrix.backend!='ptx'
|
||||
run: python -m pytest -n=auto test/ -k '${{matrix.backend=='llvm'&&'not (test_nn.py and test_conv_transpose2d)'||'test'}}' -m 'not exclude_${{matrix.backend}}'
|
||||
- name: Run pytest (cuda)
|
||||
if: matrix.backend=='cuda'
|
||||
run: python -m pytest -n=auto test/ -k 'not (half or test_efficientnet_safetensors) and not (test_conv2d and test_tensor.py)' -m 'not exclude_cuda' --ignore=test/external --ignore=test/models
|
||||
- name: Run pytest (ptx)
|
||||
if: matrix.backend=='ptx'
|
||||
run: python -m pytest -n=auto test/ -k 'not (half or test_efficientnet_safetensors) and not (test_conv2d and test_tensor.py)' -m 'not exclude_cuda' --ignore=test/external --ignore=test/models
|
||||
|
||||
testunicorn:
|
||||
name: ARM64 unicorn Test
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@v3
|
||||
- name: Set up Python 3.11
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: 3.11
|
||||
- name: Cache python packages
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ${{ env.Python3_ROOT_DIR }}/lib/python3.11/site-packages
|
||||
key: testing-arm-packages-${{ hashFiles('*/setup.py') }}
|
||||
- name: Install cross-assembler
|
||||
run: |
|
||||
sudo apt update -y
|
||||
sudo apt install -y --no-install-recommends gcc-aarch64-linux-gnu
|
||||
- name: Install dependencies
|
||||
run: pip install -e '.[testing,arm]' --extra-index-url https://download.pytorch.org/whl/cpu
|
||||
- name: Test arm
|
||||
run: CI=1 ARM64=1 CLANG=1 python -m pytest -n=auto test/ -k 'not (test_nn.py and (test_conv_transpose2d or test_conv2d))' --ignore=test/models --ignore=test/test_speed_v_torch.py --ignore=test/test_net_speed.py --ignore=test/test_specific_conv.py --ignore=test/unit/test_disk_tensor.py
|
||||
-41
@@ -1,41 +0,0 @@
|
||||
__pycache__
|
||||
.venv/
|
||||
.vscode
|
||||
notebooks
|
||||
.*.swp
|
||||
.*.swo
|
||||
*.pyc
|
||||
*.so
|
||||
build
|
||||
/dist
|
||||
*.egg-info
|
||||
/env
|
||||
a.out
|
||||
boxes.jpg
|
||||
pandecode.dump
|
||||
vertex.bin
|
||||
recognize*
|
||||
.idea
|
||||
disassemblers/applegpu
|
||||
disassemblers/cuda_ioctl_sniffer
|
||||
*.prof
|
||||
extra/datasets/cifar-10-python.tar.gz
|
||||
extra/datasets/librispeech/
|
||||
extra/datasets/imagenet/
|
||||
extra/datasets/kits19/
|
||||
extra/datasets/squad/
|
||||
extra/datasets/img_align_celeba*
|
||||
extra/datasets/open-images-v6-mlperf
|
||||
extra/datasets/kits/
|
||||
extra/datasets/COCO/
|
||||
extra/datasets/audio*
|
||||
venv
|
||||
examples/net.*[js,json,safetensors]
|
||||
node_modules
|
||||
package.json
|
||||
package-lock.json
|
||||
temp
|
||||
*.csv
|
||||
.coverage
|
||||
coverage.xml
|
||||
htmlcov
|
||||
@@ -1,33 +0,0 @@
|
||||
repos:
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: docs
|
||||
name: docs
|
||||
entry: python3 docs/abstractions.py
|
||||
language: system
|
||||
always_run: true
|
||||
pass_filenames: false
|
||||
- id: flake8
|
||||
name: flake8
|
||||
entry: flake8 --statistics -j4
|
||||
language: system
|
||||
always_run: true
|
||||
pass_filenames: false
|
||||
- id: mypy
|
||||
name: mypy
|
||||
entry: mypy tinygrad/ extra/helpers.py --check-untyped-defs --explicit-package-bases --warn-unreachable # --warn-return-any
|
||||
language: system
|
||||
always_run: true
|
||||
pass_filenames: false
|
||||
- id: tests
|
||||
name: subset of (CPU) tests
|
||||
entry: env CPU=1 pytest test/unit/ test/test_ops.py test/test_dtype.py
|
||||
language: system
|
||||
always_run: true
|
||||
pass_filenames: false
|
||||
- id: pylint
|
||||
name: pylint
|
||||
entry: pylint tinygrad/
|
||||
language: system
|
||||
always_run: true
|
||||
pass_filenames: false
|
||||
@@ -1,472 +0,0 @@
|
||||
[MASTER]
|
||||
|
||||
# A comma-separated list of package or module names from where C extensions may
|
||||
# be loaded. Extensions are loading into the active Python interpreter and may
|
||||
# run arbitrary code
|
||||
extension-pkg-whitelist=scipy,cereal.messaging.messaging_pyx,PyQt5,av
|
||||
|
||||
# Add files or directories to the blacklist. They should be base names, not
|
||||
# paths.
|
||||
ignore=CVS
|
||||
|
||||
# Add files or directories matching the regex patterns to the blacklist. The
|
||||
# regex matches against base names, not paths.
|
||||
ignore-patterns=
|
||||
|
||||
# Python code to execute, usually for sys.path manipulation such as
|
||||
# pygtk.require().
|
||||
#init-hook=
|
||||
|
||||
# Use multiple processes to speed up Pylint.
|
||||
jobs=4
|
||||
|
||||
# List of plugins (as comma separated values of python modules names) to load,
|
||||
# usually to register additional checkers.
|
||||
load-plugins=
|
||||
|
||||
# Pickle collected data for later comparisons.
|
||||
persistent=yes
|
||||
|
||||
# Specify a configuration file.
|
||||
#rcfile=
|
||||
|
||||
# When enabled, pylint would attempt to guess common misconfiguration and emit
|
||||
# user-friendly hints instead of false-positive error messages
|
||||
suggestion-mode=yes
|
||||
|
||||
# Allow loading of arbitrary C extensions. Extensions are imported into the
|
||||
# active Python interpreter and may run arbitrary code.
|
||||
unsafe-load-any-extension=no
|
||||
|
||||
|
||||
[MESSAGES CONTROL]
|
||||
|
||||
# Only show warnings with the listed confidence levels. Leave empty to show
|
||||
# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED
|
||||
confidence=
|
||||
|
||||
# Disable the message, report, category or checker with the given id(s). You
|
||||
# can either give multiple identifiers separated by comma (,) or put this
|
||||
# option multiple times (only on the command line, not in the configuration
|
||||
# file where it should appear only once).You can also use "--disable=all" to
|
||||
# disable everything first and then reenable specific checks. For example, if
|
||||
# you want to run only the similarities checker, you can use "--disable=all
|
||||
# --enable=similarities". If you want to run only the classes checker, but have
|
||||
# no Warning level messages displayed, use"--disable=all --enable=classes
|
||||
# --disable=W"
|
||||
disable=C,R,W0613,W0511,W0212,W0201,W0106,W0603,W0621,W0703,W1201,W1203,E1136,W1514,E1101,W0221,W0105,E0401
|
||||
# E1101 for mlops binding
|
||||
# W0221 for Function class
|
||||
# W0105 for comment strings
|
||||
# E0401 for missing imports
|
||||
|
||||
# Enable the message, report, category or checker with the given id(s). You can
|
||||
# either give multiple identifier separated by comma (,) or put this option
|
||||
# multiple time (only on the command line, not in the configuration file where
|
||||
# it should appear only once). See also the "--disable" option for examples.
|
||||
enable=c-extension-no-member,use-a-generator, no-else-return
|
||||
|
||||
|
||||
[REPORTS]
|
||||
|
||||
# Python expression which should return a note less than 10 (10 is the highest
|
||||
# note). You have access to the variables errors warning, statement which
|
||||
# respectively contain the number of errors / warnings messages and the total
|
||||
# number of statements analyzed. This is used by the global evaluation report
|
||||
# (RP0004).
|
||||
evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
|
||||
|
||||
# Template used to display messages. This is a python new-style format string
|
||||
# used to format the message information. See doc for all details
|
||||
#msg-template=
|
||||
|
||||
# Set the output format. Available formats are text, parseable, colorized, json
|
||||
# and msvs (visual studio).You can also give a reporter class, eg
|
||||
# mypackage.mymodule.MyReporterClass.
|
||||
output-format=text
|
||||
|
||||
# Tells whether to display a full report or only the messages
|
||||
reports=no
|
||||
|
||||
# Activate the evaluation score.
|
||||
score=yes
|
||||
|
||||
|
||||
[REFACTORING]
|
||||
|
||||
# Maximum number of nested blocks for function / method body
|
||||
max-nested-blocks=5
|
||||
|
||||
# Complete name of functions that never returns. When checking for
|
||||
# inconsistent-return-statements if a never returning function is called then
|
||||
# it will be considered as an explicit return statement and no message will be
|
||||
# printed.
|
||||
never-returning-functions=optparse.Values,sys.exit
|
||||
|
||||
|
||||
[LOGGING]
|
||||
|
||||
# Logging modules to check that the string format arguments are in logging
|
||||
# function parameter format
|
||||
logging-modules=logging
|
||||
|
||||
|
||||
[SPELLING]
|
||||
|
||||
# Limits count of emitted suggestions for spelling mistakes
|
||||
max-spelling-suggestions=4
|
||||
|
||||
# Spelling dictionary name. Available dictionaries: none. To make it working
|
||||
# install python-enchant package.
|
||||
spelling-dict=
|
||||
|
||||
# List of comma separated words that should not be checked.
|
||||
spelling-ignore-words=
|
||||
|
||||
# A path to a file that contains private dictionary; one word per line.
|
||||
spelling-private-dict-file=
|
||||
|
||||
# Tells whether to store unknown words to indicated private dictionary in
|
||||
# --spelling-private-dict-file option instead of raising a message.
|
||||
spelling-store-unknown-words=no
|
||||
|
||||
|
||||
[MISCELLANEOUS]
|
||||
|
||||
# List of note tags to take in consideration, separated by a comma.
|
||||
notes=FIXME,
|
||||
XXX,
|
||||
TODO
|
||||
|
||||
|
||||
[SIMILARITIES]
|
||||
|
||||
# Ignore comments when computing similarities.
|
||||
ignore-comments=yes
|
||||
|
||||
# Ignore docstrings when computing similarities.
|
||||
ignore-docstrings=yes
|
||||
|
||||
# Ignore imports when computing similarities.
|
||||
ignore-imports=no
|
||||
|
||||
# Minimum lines number of a similarity.
|
||||
min-similarity-lines=4
|
||||
|
||||
|
||||
[TYPECHECK]
|
||||
|
||||
# List of decorators that produce context managers, such as
|
||||
# contextlib.contextmanager. Add to this list to register other decorators that
|
||||
# produce valid context managers.
|
||||
contextmanager-decorators=contextlib.contextmanager
|
||||
|
||||
# List of members which are set dynamically and missed by pylint inference
|
||||
# system, and so shouldn't trigger E1101 when accessed. Python regular
|
||||
# expressions are accepted.
|
||||
generated-members=capnp.* cereal.* pygame.* zmq.* setproctitle.* smbus2.* usb1.* serial.* cv2.* ft4222.* carla.*
|
||||
|
||||
# Tells whether missing members accessed in mixin class should be ignored. A
|
||||
# mixin class is detected if its name ends with "mixin" (case insensitive).
|
||||
ignore-mixin-members=yes
|
||||
|
||||
# This flag controls whether pylint should warn about no-member and similar
|
||||
# checks whenever an opaque object is returned when inferring. The inference
|
||||
# can return multiple potential results while evaluating a Python object, but
|
||||
# some branches might not be evaluated, which results in partial inference. In
|
||||
# that case, it might be useful to still emit no-member and other checks for
|
||||
# the rest of the inferred objects.
|
||||
ignore-on-opaque-inference=yes
|
||||
|
||||
# List of class names for which member attributes should not be checked (useful
|
||||
# for classes with dynamically set attributes). This supports the use of
|
||||
# qualified names.
|
||||
ignored-classes=optparse.Values,thread._local,_thread._local
|
||||
|
||||
# List of module names for which member attributes should not be checked
|
||||
# (useful for modules/projects where namespaces are manipulated during runtime
|
||||
# and thus existing member attributes cannot be deduced by static analysis. It
|
||||
# supports qualified module names, as well as Unix pattern matching.
|
||||
ignored-modules=flask setproctitle usb1 flask.ext.socketio smbus2 usb1.*
|
||||
|
||||
# Show a hint with possible names when a member name was not found. The aspect
|
||||
# of finding the hint is based on edit distance.
|
||||
missing-member-hint=yes
|
||||
|
||||
# The minimum edit distance a name should have in order to be considered a
|
||||
# similar match for a missing member name.
|
||||
missing-member-hint-distance=1
|
||||
|
||||
# The total number of similar names that should be taken in consideration when
|
||||
# showing a hint for a missing member.
|
||||
missing-member-max-choices=1
|
||||
|
||||
|
||||
[VARIABLES]
|
||||
|
||||
# List of additional names supposed to be defined in builtins. Remember that
|
||||
# you should avoid to define new builtins when possible.
|
||||
additional-builtins=
|
||||
|
||||
# Tells whether unused global variables should be treated as a violation.
|
||||
allow-global-unused-variables=yes
|
||||
|
||||
# List of strings which can identify a callback function by name. A callback
|
||||
# name must start or end with one of those strings.
|
||||
callbacks=cb_,
|
||||
_cb
|
||||
|
||||
# A regular expression matching the name of dummy variables (i.e. expectedly
|
||||
# not used).
|
||||
dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_
|
||||
|
||||
# Argument names that match this expression will be ignored. Default to name
|
||||
# with leading underscore
|
||||
ignored-argument-names=_.*|^ignored_|^unused_
|
||||
|
||||
# Tells whether we should check for unused import in __init__ files.
|
||||
init-import=no
|
||||
|
||||
# List of qualified module names which can have objects that can redefine
|
||||
# builtins.
|
||||
redefining-builtins-modules=six.moves,past.builtins,future.builtins
|
||||
|
||||
|
||||
[FORMAT]
|
||||
|
||||
# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
|
||||
expected-line-ending-format=
|
||||
|
||||
# Regexp for a line that is allowed to be longer than the limit.
|
||||
ignore-long-lines=^\s*(# )?<?https?://\S+>?$
|
||||
|
||||
# Number of spaces of indent required inside a hanging or continued line.
|
||||
indent-after-paren=4
|
||||
|
||||
# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
|
||||
# tab).
|
||||
indent-string=' '
|
||||
|
||||
# Maximum number of characters on a single line.
|
||||
max-line-length=100
|
||||
|
||||
# Maximum number of lines in a module
|
||||
max-module-lines=1000
|
||||
|
||||
# Allow the body of a class to be on the same line as the declaration if body
|
||||
# contains single statement.
|
||||
single-line-class-stmt=no
|
||||
|
||||
# Allow the body of an if to be on the same line as the test if there is no
|
||||
# else.
|
||||
single-line-if-stmt=no
|
||||
|
||||
|
||||
[BASIC]
|
||||
|
||||
# Naming style matching correct argument names
|
||||
argument-naming-style=snake_case
|
||||
|
||||
# Regular expression matching correct argument names. Overrides argument-
|
||||
# naming-style
|
||||
#argument-rgx=
|
||||
|
||||
# Naming style matching correct attribute names
|
||||
attr-naming-style=snake_case
|
||||
|
||||
# Regular expression matching correct attribute names. Overrides attr-naming-
|
||||
# style
|
||||
#attr-rgx=
|
||||
|
||||
# Bad variable names which should always be refused, separated by a comma
|
||||
bad-names=foo,
|
||||
bar,
|
||||
baz,
|
||||
toto,
|
||||
tutu,
|
||||
tata
|
||||
|
||||
# Naming style matching correct class attribute names
|
||||
class-attribute-naming-style=any
|
||||
|
||||
# Regular expression matching correct class attribute names. Overrides class-
|
||||
# attribute-naming-style
|
||||
#class-attribute-rgx=
|
||||
|
||||
# Naming style matching correct class names
|
||||
class-naming-style=PascalCase
|
||||
|
||||
# Regular expression matching correct class names. Overrides class-naming-style
|
||||
#class-rgx=
|
||||
|
||||
# Naming style matching correct constant names
|
||||
const-naming-style=UPPER_CASE
|
||||
|
||||
# Regular expression matching correct constant names. Overrides const-naming-
|
||||
# style
|
||||
#const-rgx=
|
||||
|
||||
# Minimum line length for functions/classes that require docstrings, shorter
|
||||
# ones are exempt.
|
||||
docstring-min-length=-1
|
||||
|
||||
# Naming style matching correct function names
|
||||
function-naming-style=snake_case
|
||||
|
||||
# Regular expression matching correct function names. Overrides function-
|
||||
# naming-style
|
||||
#function-rgx=
|
||||
|
||||
# Good variable names which should always be accepted, separated by a comma
|
||||
good-names=i,
|
||||
j,
|
||||
k,
|
||||
ex,
|
||||
Run,
|
||||
_
|
||||
|
||||
# Include a hint for the correct naming format with invalid-name
|
||||
include-naming-hint=no
|
||||
|
||||
# Naming style matching correct inline iteration names
|
||||
inlinevar-naming-style=any
|
||||
|
||||
# Regular expression matching correct inline iteration names. Overrides
|
||||
# inlinevar-naming-style
|
||||
#inlinevar-rgx=
|
||||
|
||||
# Naming style matching correct method names
|
||||
method-naming-style=snake_case
|
||||
|
||||
# Regular expression matching correct method names. Overrides method-naming-
|
||||
# style
|
||||
#method-rgx=
|
||||
|
||||
# Naming style matching correct module names
|
||||
module-naming-style=snake_case
|
||||
|
||||
# Regular expression matching correct module names. Overrides module-naming-
|
||||
# style
|
||||
#module-rgx=
|
||||
|
||||
# Colon-delimited sets of names that determine each other's naming style when
|
||||
# the name regexes allow several styles.
|
||||
name-group=
|
||||
|
||||
# Regular expression which should only match function or class names that do
|
||||
# not require a docstring.
|
||||
no-docstring-rgx=^_
|
||||
|
||||
# List of decorators that produce properties, such as abc.abstractproperty. Add
|
||||
# to this list to register other decorators that produce valid properties.
|
||||
property-classes=abc.abstractproperty
|
||||
|
||||
# Naming style matching correct variable names
|
||||
variable-naming-style=snake_case
|
||||
|
||||
# Regular expression matching correct variable names. Overrides variable-
|
||||
# naming-style
|
||||
#variable-rgx=
|
||||
|
||||
|
||||
[DESIGN]
|
||||
|
||||
# Maximum number of arguments for function / method
|
||||
max-args=5
|
||||
|
||||
# Maximum number of attributes for a class (see R0902).
|
||||
max-attributes=7
|
||||
|
||||
# Maximum number of boolean expressions in a if statement
|
||||
max-bool-expr=5
|
||||
|
||||
# Maximum number of branch for function / method body
|
||||
max-branches=12
|
||||
|
||||
# Maximum number of locals for function / method body
|
||||
max-locals=15
|
||||
|
||||
# Maximum number of parents for a class (see R0901).
|
||||
max-parents=7
|
||||
|
||||
# Maximum number of public methods for a class (see R0904).
|
||||
max-public-methods=20
|
||||
|
||||
# Maximum number of return / yield for function / method body
|
||||
max-returns=6
|
||||
|
||||
# Maximum number of statements in function / method body
|
||||
max-statements=50
|
||||
|
||||
# Minimum number of public methods for a class (see R0903).
|
||||
min-public-methods=2
|
||||
|
||||
|
||||
[CLASSES]
|
||||
|
||||
# List of method names used to declare (i.e. assign) instance attributes.
|
||||
defining-attr-methods=__init__,
|
||||
__new__,
|
||||
setUp
|
||||
|
||||
# List of member names, which should be excluded from the protected access
|
||||
# warning.
|
||||
exclude-protected=_asdict,
|
||||
_fields,
|
||||
_replace,
|
||||
_source,
|
||||
_make
|
||||
|
||||
# List of valid names for the first argument in a class method.
|
||||
valid-classmethod-first-arg=cls
|
||||
|
||||
# List of valid names for the first argument in a metaclass class method.
|
||||
valid-metaclass-classmethod-first-arg=mcs
|
||||
|
||||
|
||||
[IMPORTS]
|
||||
|
||||
# Allow wildcard imports from modules that define __all__.
|
||||
allow-wildcard-with-all=no
|
||||
|
||||
# Analyse import fallback blocks. This can be used to support both Python 2 and
|
||||
# 3 compatible code, which means that the block might have code that exists
|
||||
# only in one or another interpreter, leading to false positives when analysed.
|
||||
analyse-fallback-blocks=no
|
||||
|
||||
# Deprecated modules which should not be used, separated by a comma
|
||||
deprecated-modules=regsub,
|
||||
TERMIOS,
|
||||
Bastion,
|
||||
rexec
|
||||
|
||||
# Create a graph of external dependencies in the given file (report RP0402 must
|
||||
# not be disabled)
|
||||
ext-import-graph=
|
||||
|
||||
# Create a graph of every (i.e. internal and external) dependencies in the
|
||||
# given file (report RP0402 must not be disabled)
|
||||
import-graph=
|
||||
|
||||
# Create a graph of internal dependencies in the given file (report RP0402 must
|
||||
# not be disabled)
|
||||
int-import-graph=
|
||||
|
||||
# Force import order to recognize a module as part of the standard
|
||||
# compatibility libraries.
|
||||
known-standard-library=
|
||||
|
||||
# Force import order to recognize a module as part of a third party library.
|
||||
known-third-party=enchant
|
||||
|
||||
[STRING]
|
||||
|
||||
# This flag controls whether the implicit-str-concat should generate a warning
|
||||
# on implicit string concatenation in sequences defined over several lines.
|
||||
check-str-concat-over-line-jumps=yes
|
||||
|
||||
[EXCEPTIONS]
|
||||
|
||||
# Exceptions that will emit a warning when being caught. Defaults to
|
||||
# "Exception"
|
||||
overgeneral-exceptions=builtins.Exception
|
||||
@@ -1,4 +0,0 @@
|
||||
*
|
||||
!*/
|
||||
|
||||
!tinygrad/**
|
||||
@@ -1,33 +0,0 @@
|
||||
# Are you ready to write high quality code?
|
||||
|
||||
The idea of tinygrad is to build a <5000 line library capable of training a wide variety of ML models at 80%+ max theoretical speed across a huge variety of hardware.
|
||||
|
||||
There is almost no boilerplate code anywhere in this library, and you should help keep it that way. If the code you are contributing to core tinygrad, in `tinygrad/`, isn't some of the highest quality code you've written in your life, either put in the effort to make it great, or don't bother. (other directories have a slightly more relaxed standard)
|
||||
|
||||
There is a linter, but it's not complete. Spend a little time reading the existing code to get a feel for the style.
|
||||
|
||||
I love PRs where I can look at them and just say, yes, this will improve the codebase and click merge. If you have an incomplete PR, feel free to post it as a draft.
|
||||
|
||||
As my operating systems professor taught me, code is written to be read by humans. We value readability over performance and line count, but low line count is often a good proxy for readability. However, any PRs that look like code golf will immediately be closed.
|
||||
|
||||
There are a few basic ways to contribute:
|
||||
|
||||
## Bug-fixes
|
||||
|
||||
These are the most straightforward. Discover a bug. Add a test to reproduce it. Write a clean fix. Submit a PR. Confirm CI passes.
|
||||
|
||||
## Conceptual Cleanups
|
||||
|
||||
This is some of the highest value work in tinygrad. If you realize two 50 line functions are basically the same thing, and you can merge them, amazing! Things that look confusing and are hard to follow are probably poorly written. If you can rewrite the code and be like, oh that's a ton simpler, by all means do so. Make sure you have good test coverage around what you are changing.
|
||||
|
||||
## Better Testing
|
||||
|
||||
Always welcome! Think about how robust and fast your tests are though. How likely is this test to catch a bug? Tests that run in CI go in `test/`, except for the ones in `test/external/`. We have a few things like fuzzers in there.
|
||||
|
||||
## Speed improvements
|
||||
|
||||
tinygrad is a JIT compiler, so speed improvements refer to both compile-time and runtime. Speed improvements to the python based compiler are welcome, but please include benchmarks and good tests around the things that you are changing. If you are sacrificing readability for speed, don't bother. Speed improvements to the generated code usually come from conceptual cleanups. Generated code improvements are probably the hardest thing to work on in tinygrad, since they must be done in a very generic way.
|
||||
|
||||
## Features
|
||||
|
||||
This is a trickier one. If there is a feature in PyTorch and numpy that you have actually seen people use, we probably want it. All new features must include good robust tests, and in general, matching the PyTorch API is good.
|
||||
@@ -1,7 +0,0 @@
|
||||
Copyright (c) 2023 George Hotz
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
@@ -1,162 +0,0 @@
|
||||
<div align="center">
|
||||
|
||||
[](https://tinygrad.org)
|
||||
|
||||
tinygrad: For something between [PyTorch](https://github.com/pytorch/pytorch) and [karpathy/micrograd](https://github.com/karpathy/micrograd). Maintained by [tiny corp](https://tinygrad.org).
|
||||
|
||||
<h3>
|
||||
|
||||
[Homepage](https://github.com/tinygrad/tinygrad) | [Documentation](/docs) | [Examples](/examples) | [Showcase](/docs/showcase.md) | [Discord](https://discord.gg/ZjZadyC7PK)
|
||||
|
||||
</h3>
|
||||
|
||||
[](https://github.com/tinygrad/tinygrad/stargazers)
|
||||
[](https://github.com/tinygrad/tinygrad/actions/workflows/test.yml)
|
||||
[](https://discord.gg/ZjZadyC7PK)
|
||||
[](https://github.com/tinygrad/tinygrad)
|
||||
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
This may not be the best deep learning framework, but it is a deep learning framework.
|
||||
|
||||
Due to its extreme simplicity, it aims to be the easiest framework to add new accelerators to, with support for both inference and training. If XLA is CISC, tinygrad is RISC.
|
||||
|
||||
tinygrad is still alpha software, but we [raised some money](https://geohot.github.io/blog/jekyll/update/2023/05/24/the-tiny-corp-raised-5M.html) to make it good. Someday, we will tape out chips.
|
||||
|
||||
## Features
|
||||
|
||||
### LLaMA and Stable Diffusion
|
||||
|
||||
tinygrad can run [LLaMA](/docs/showcase.md#llama) and [Stable Diffusion](/docs/showcase.md#stable-diffusion)!
|
||||
|
||||
### Laziness
|
||||
|
||||
Try a matmul. See how, despite the style, it is fused into one kernel with the power of laziness.
|
||||
|
||||
```sh
|
||||
DEBUG=3 python3 -c "from tinygrad.tensor import Tensor;
|
||||
N = 1024; a, b = Tensor.rand(N, N), Tensor.rand(N, N);
|
||||
c = (a.reshape(N, 1, N) * b.permute(1,0).reshape(1, N, N)).sum(axis=2);
|
||||
print((c.numpy() - (a.numpy() @ b.numpy())).mean())"
|
||||
```
|
||||
|
||||
And we can change `DEBUG` to `4` to see the generated code.
|
||||
|
||||
### Neural networks
|
||||
|
||||
As it turns out, 90% of what you need for neural networks are a decent autograd/tensor library.
|
||||
Throw in an optimizer, a data loader, and some compute, and you have all you need.
|
||||
|
||||
#### Neural network example (from test/models/test_mnist.py)
|
||||
|
||||
```py
|
||||
from tinygrad.tensor import Tensor
|
||||
import tinygrad.nn.optim as optim
|
||||
|
||||
class TinyBobNet:
|
||||
def __init__(self):
|
||||
self.l1 = Tensor.uniform(784, 128)
|
||||
self.l2 = Tensor.uniform(128, 10)
|
||||
|
||||
def forward(self, x):
|
||||
return x.dot(self.l1).relu().dot(self.l2).log_softmax()
|
||||
|
||||
model = TinyBobNet()
|
||||
optim = optim.SGD([model.l1, model.l2], lr=0.001)
|
||||
|
||||
# ... complete data loader here
|
||||
|
||||
out = model.forward(x)
|
||||
loss = out.mul(y).mean()
|
||||
optim.zero_grad()
|
||||
loss.backward()
|
||||
optim.step()
|
||||
```
|
||||
|
||||
## Accelerators
|
||||
|
||||
tinygrad already supports numerous accelerators, including:
|
||||
|
||||
- [x] [CPU](tinygrad/runtime/ops_cpu.py)
|
||||
- [x] [GPU (OpenCL)](tinygrad/runtime/ops_gpu.py)
|
||||
- [x] [C Code (Clang)](tinygrad/runtime/ops_clang.py)
|
||||
- [x] [LLVM](tinygrad/runtime/ops_llvm.py)
|
||||
- [x] [METAL](tinygrad/runtime/ops_metal.py)
|
||||
- [x] [CUDA](tinygrad/runtime/ops_cuda.py)
|
||||
- [x] [Triton](extra/accel/triton/ops_triton.py)
|
||||
- [x] [PyTorch](tinygrad/runtime/ops_torch.py)
|
||||
- [x] [HIP](tinygrad/runtime/ops_hip.py)
|
||||
- [x] [WebGPU](tinygrad/runtime/ops_webgpu.py)
|
||||
|
||||
And it is easy to add more! Your accelerator of choice only needs to support a total of 26 (optionally 27) low level ops.
|
||||
More information can be found in the [documentation for adding new accelerators](/docs/adding_new_accelerators.md).
|
||||
|
||||
## Installation
|
||||
|
||||
The current recommended way to install tinygrad is from source.
|
||||
|
||||
### From source
|
||||
|
||||
```sh
|
||||
git clone https://github.com/tinygrad/tinygrad.git
|
||||
cd tinygrad
|
||||
python3 -m pip install -e .
|
||||
```
|
||||
Don't forget the `.` at the end!
|
||||
|
||||
## Documentation
|
||||
|
||||
Documentation along with a quick start guide can be found in the [docs/](/docs) directory.
|
||||
|
||||
### Quick example comparing to PyTorch
|
||||
|
||||
```py
|
||||
from tinygrad.tensor import Tensor
|
||||
|
||||
x = Tensor.eye(3, requires_grad=True)
|
||||
y = Tensor([[2.0,0,-2.0]], requires_grad=True)
|
||||
z = y.matmul(x).sum()
|
||||
z.backward()
|
||||
|
||||
print(x.grad.numpy()) # dz/dx
|
||||
print(y.grad.numpy()) # dz/dy
|
||||
```
|
||||
|
||||
The same thing but in PyTorch:
|
||||
```py
|
||||
import torch
|
||||
|
||||
x = torch.eye(3, requires_grad=True)
|
||||
y = torch.tensor([[2.0,0,-2.0]], requires_grad=True)
|
||||
z = y.matmul(x).sum()
|
||||
z.backward()
|
||||
|
||||
print(x.grad.numpy()) # dz/dx
|
||||
print(y.grad.numpy()) # dz/dy
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
There has been a lot of interest in tinygrad lately. Here are some basic guidelines for contributing:
|
||||
|
||||
- Bug fixes are the best and always welcome! Like [this one](https://github.com/tinygrad/tinygrad/pull/421/files).
|
||||
- If you don't understand the code you are changing, don't change it!
|
||||
- All code golf PRs will be closed, but [conceptual cleanups](https://github.com/tinygrad/tinygrad/pull/372/files) are great.
|
||||
- Features are welcome. Though if you are adding a feature, you need to include tests.
|
||||
- Improving test coverage is great, with reliable non-brittle tests.
|
||||
|
||||
Additional guidelines can be found in [CONTRIBUTING.md](/CONTRIBUTING.md).
|
||||
|
||||
### Running tests
|
||||
|
||||
For more examples on how to run the full test suite please refer to the [CI workflow](.github/workflows/test.yml).
|
||||
|
||||
Some examples:
|
||||
```sh
|
||||
python3 -m pip install -e '.[testing]'
|
||||
python3 -m pytest
|
||||
python3 -m pytest -v -k TestTrain
|
||||
python3 ./test/models/test_train.py TestTrain.test_efficientnet
|
||||
```
|
||||
@@ -0,0 +1,54 @@
|
||||
# abstractions2 goes from back to front, here we will go from front to back
|
||||
|
||||
# *****
|
||||
# 0. Load mnist on the device
|
||||
|
||||
from tinygrad.nn.datasets import mnist
|
||||
X_train, Y_train, _, _ = mnist()
|
||||
X_train = X_train.float()
|
||||
X_train -= X_train.mean()
|
||||
|
||||
# *****
|
||||
# 1. Define an MNIST model.
|
||||
|
||||
from tinygrad import Tensor, Context
|
||||
|
||||
l1 = Tensor.kaiming_uniform(128, 784)
|
||||
l2 = Tensor.kaiming_uniform(10, 128)
|
||||
def model(x): return x.flatten(1).dot(l1.T).relu().dot(l2.T)
|
||||
l1n, l2n = l1.numpy(), l2.numpy()
|
||||
|
||||
# *****
|
||||
# 2. Choose a batch for training and do the backward pass.
|
||||
|
||||
from tinygrad.nn.optim import SGD
|
||||
optim = SGD([l1, l2])
|
||||
|
||||
with Context(TRAINING=1):
|
||||
X, Y = X_train[(samples:=Tensor.randint(128, high=X_train.shape[0]))], Y_train[samples]
|
||||
optim.zero_grad()
|
||||
model(X).sparse_categorical_crossentropy(Y).backward()
|
||||
optim.schedule_step() # this will step the optimizer without running realize
|
||||
|
||||
# *****
|
||||
# 3. Create a schedule (linear uop).
|
||||
|
||||
# The weight Tensors have been assigned to, but not yet realized. Everything is still lazy at this point
|
||||
# l1.uop and l2.uop define a computation graph
|
||||
|
||||
from tinygrad.engine.realize import run_linear
|
||||
linear = Tensor.schedule_linear(l1, l2)
|
||||
|
||||
print(f"The schedule contains {len(linear.src)} items.")
|
||||
for call in linear.src: print(str(call)[:80])
|
||||
|
||||
# *****
|
||||
# 4. Lower and run the schedule (linear uop).
|
||||
|
||||
run_linear(linear)
|
||||
|
||||
# *****
|
||||
# 5. Print the weight change
|
||||
|
||||
print("first weight change\n", l1.numpy()-l1n)
|
||||
print("second weight change\n", l2.numpy()-l2n)
|
||||
@@ -0,0 +1,251 @@
|
||||
# tinygrad allows you to write kernels at many different abstractions levels.
|
||||
# This is for RDNA3, but if you don't have one you can run with the emulator
|
||||
# PYTHONPATH="." DEV=MOCKPCI+AMD
|
||||
|
||||
from tinygrad import Tensor, Context, GlobalCounters, UOp, Device
|
||||
from tinygrad.helpers import DEV, DEBUG, getenv
|
||||
from tinygrad.uop.ops import AxisType, KernelInfo, Ops
|
||||
from tinygrad.dtype import AddrSpace, dtypes
|
||||
from tinygrad.runtime.autogen.amd.rdna3.ins import *
|
||||
|
||||
def eval_harness(name, tensor, fxn, check=None):
|
||||
print(f"***** {name}")
|
||||
GlobalCounters.reset()
|
||||
with Context(DEBUG=max(DEBUG.value, 2)): out = fxn(tensor).item()
|
||||
assert check is None or abs(out - check) < abs(check) * 1e-3, f"out was wrong {out}, expected {check}, off by {out/check}x"
|
||||
print(f"computed in {GlobalCounters.time_sum_s*1000:.2f} ms, {(a.nbytes()/1e9)/GlobalCounters.time_sum_s:.2f} GB/s")
|
||||
return out
|
||||
|
||||
SZ = 256*1024 if DEV.interface.startswith("MOCK") else 1024*1024*1024
|
||||
|
||||
def example_2_hip(a:Tensor, correct):
|
||||
GLOBALS = 1024
|
||||
THREADS = 256
|
||||
def hip_reduce_sum(out:UOp, buf:UOp) -> UOp:
|
||||
assert SZ % (GLOBALS * THREADS) == 0
|
||||
CHUNK = SZ // (GLOBALS * THREADS)
|
||||
# NOTE: tinygrad doesn't populate HIP hidden kernargs, so blockDim.x/gridDim.x read as 0.
|
||||
# We hardcode block/grid sizes as constexpr to avoid any dependency on those builtins.
|
||||
code = f"""
|
||||
#include <hip/hip_runtime.h>
|
||||
constexpr unsigned int BLOCK = {THREADS};
|
||||
constexpr unsigned int CHUNK = {CHUNK};
|
||||
extern "C" __global__ void hip_reduce_sum_kernel(float* __restrict__ block_sums, const float* __restrict__ x) {{
|
||||
__shared__ float sdata[BLOCK];
|
||||
|
||||
unsigned int tid = threadIdx.x;
|
||||
unsigned int gid = blockIdx.x * BLOCK + tid;
|
||||
|
||||
// Each thread sums CHUNK consecutive elements from its own region
|
||||
float sum = 0.0f;
|
||||
const float* base = x + gid * CHUNK;
|
||||
#pragma unroll 16
|
||||
for (unsigned int k = 0; k < CHUNK; k++) {{
|
||||
sum += base[k];
|
||||
}}
|
||||
|
||||
sdata[tid] = sum;
|
||||
__syncthreads();
|
||||
|
||||
// Block reduction in shared memory
|
||||
for (unsigned int s = BLOCK / 2; s > 0; s >>= 1) {{
|
||||
if (tid < s) {{
|
||||
sdata[tid] += sdata[tid + s];
|
||||
}}
|
||||
__syncthreads();
|
||||
}}
|
||||
|
||||
// One partial sum per block
|
||||
if (tid == 0) {{
|
||||
block_sums[blockIdx.x] = sdata[0];
|
||||
}}
|
||||
}}"""
|
||||
|
||||
# TODO: remove the need for the compiler here, you should just be able to remove Ops.BINARY
|
||||
from tinygrad.runtime.support.compiler_amd import HIPCCCompiler
|
||||
lib = HIPCCCompiler(Device[Device.DEFAULT].renderer.target.arch, []).compile_cached(code)
|
||||
# the sink specifies the GLOBAL and LOCAL sizes, along with the input buffers and name
|
||||
sink = UOp.sink(UOp.special(GLOBALS, 'gidx0'), UOp.special(THREADS, 'lidx0'), out, buf,
|
||||
arg=KernelInfo(name="hip_reduce_sum_kernel"))
|
||||
return UOp(Ops.PROGRAM, src=(sink, UOp(Ops.LINEAR, src=(*sink.src, sink)), UOp(Ops.SOURCE, arg=code), UOp(Ops.BINARY, arg=lib)))
|
||||
eval_harness("HIP kernel", a, lambda x: Tensor.empty(GLOBALS).custom_kernel(x, fxn=hip_reduce_sum)[0].sum(), check=correct)
|
||||
|
||||
def example_3_custom_uop(a:Tensor, correct):
|
||||
# This GPU has 32 CUs, keep them all busy
|
||||
CU_COUNT = 32
|
||||
def custom_sum(out:UOp, buf:UOp) -> UOp:
|
||||
LCLS = 256
|
||||
buf = buf.reshape(CU_COUNT, -1, LCLS)
|
||||
|
||||
glbl = UOp.range(CU_COUNT, 0, AxisType.GLOBAL)
|
||||
lane = UOp.range(LCLS, 1, AxisType.LOCAL)
|
||||
|
||||
# accumulate the globals into a per lane accumulator
|
||||
reduce_loop = UOp.range(buf.shape[1], 2, AxisType.REDUCE)
|
||||
acc = UOp.placeholder((1,), dtypes.float, slot=6, addrspace=AddrSpace.REG)
|
||||
acc = acc.after(acc.store(0))
|
||||
acc = acc.after(acc[0].store(acc.after(reduce_loop)[0] + buf[glbl, reduce_loop, lane]).end(reduce_loop))
|
||||
|
||||
# store all the per lane accumulators to LOCAL
|
||||
local_accs = UOp.placeholder((LCLS,), dtypes.float, slot=0, addrspace=AddrSpace.LOCAL)
|
||||
local_accs = local_accs.after(local_accs[lane].store(acc[0]))
|
||||
|
||||
# accumulate LOCALs into a single per CU accumulator
|
||||
late_reduce_loop = UOp.range(LCLS, 3, AxisType.REDUCE)
|
||||
acc2 = UOp.placeholder((1,), dtypes.float, slot=7, addrspace=AddrSpace.REG)
|
||||
acc2 = acc2.after(acc2.store(0))
|
||||
acc2 = acc2.after(acc2[0].store(acc2.after(late_reduce_loop)[0] + local_accs[late_reduce_loop]).end(late_reduce_loop))[0]
|
||||
|
||||
# store (NOTE: since the address doesn't depend on the warp, this will be automatically gated)
|
||||
return out[glbl].store(acc2).end(lane, glbl).sink(arg=KernelInfo(opts_to_apply=()))
|
||||
|
||||
eval_harness("custom UOp kernel", a, lambda x: Tensor.empty(CU_COUNT).custom_kernel(x, fxn=custom_sum)[0].sum(), check=correct)
|
||||
|
||||
def example_5_custom_assembly(a:Tensor, correct):
|
||||
# Kernel class copied from amd_asm_matmul
|
||||
class Kernel:
|
||||
def __init__(self): self.instructions, self.labels, self.pos = [], {}, 0
|
||||
def label(self, name): self.labels[name] = self.pos
|
||||
def emit(self, inst, target=None):
|
||||
self.instructions.append(inst)
|
||||
inst._target, inst._pos = target, self.pos
|
||||
self.pos += inst.size()
|
||||
return inst
|
||||
def waitcnt(self, lgkm=None, vm=None):
|
||||
# Wait for memory operations. lgkm=N waits until N lgkm ops remain, vm=N waits until N vmem ops remain.
|
||||
vmcnt, lgkmcnt, expcnt = vm if vm is not None else 63, lgkm if lgkm is not None else 63, 7
|
||||
waitcnt = (expcnt & 0x7) | ((lgkmcnt & 0x3f) << 4) | ((vmcnt & 0x3f) << 10)
|
||||
self.emit(s_waitcnt(simm16=waitcnt))
|
||||
def finalize(self, sink:UOp) -> UOp:
|
||||
for inst in self.instructions:
|
||||
if inst._target is None: continue
|
||||
offset_dwords = (self.labels[inst._target] - inst._pos - inst.size()) // 4
|
||||
if not -32768 <= offset_dwords <= 32767: raise ValueError(f"branch to '{inst._target}' offset {offset_dwords} exceeds simm16 range")
|
||||
inst.simm16 = offset_dwords
|
||||
return UOp(Ops.PROGRAM, src=(sink, UOp(Ops.LINEAR, src=tuple([UOp(Ops.INS, arg=x) for x in self.instructions]))))
|
||||
|
||||
CU_COUNT = 32
|
||||
LANES = 64
|
||||
def asm_sum(out:UOp, buf:UOp) -> UOp:
|
||||
V_LANE_ID = 0 # lane_id set on startup
|
||||
S_WORKGROUP_X = 2 # workgroup_id_x
|
||||
S_LOOP_CTR = 3
|
||||
k = Kernel()
|
||||
# mul lane id by 16 for offsets (4 for float, 4 for b128)
|
||||
k.emit(v_mul_lo_u32(v[0], v[V_LANE_ID], 16))
|
||||
k.emit(v_add_nc_u32_e32(v[1], 4096, v[0]))
|
||||
k.emit(v_add_nc_u32_e32(v[2], 4096, v[1]))
|
||||
k.emit(v_add_nc_u32_e32(v[3], 4096, v[2]))
|
||||
# load both addresses
|
||||
k.emit(s_load_b128(sdata=s[4:7], sbase=s[0:1], offset=0x0, soffset=NULL))
|
||||
k.waitcnt(lgkm=0)
|
||||
# offset buffer pointer by workgroup_id_x * chunk_size_bytes
|
||||
k.emit(s_mul_i32(s[S_LOOP_CTR], s[S_WORKGROUP_X], buf.numel()*4//CU_COUNT))
|
||||
k.emit(s_add_u32(s[6], s[6], s[S_LOOP_CTR]))
|
||||
k.emit(s_addc_u32(s[7], s[7], 0))
|
||||
# zero the accumulators
|
||||
k.emit(VOPD(VOPDOp.V_DUAL_MOV_B32, VOPDOp.V_DUAL_MOV_B32, vdstx=v[4], vdsty=v[5], srcx0=0, srcy0=0))
|
||||
k.emit(VOPD(VOPDOp.V_DUAL_MOV_B32, VOPDOp.V_DUAL_MOV_B32, vdstx=v[6], vdsty=v[7], srcx0=0, srcy0=0))
|
||||
|
||||
def emit_loads(base_vreg, reg_len):
|
||||
assert reg_len%4 == 0
|
||||
k.emit(s_clause(simm16=(reg_len//4)-1))
|
||||
for i in range(reg_len//4):
|
||||
offset = i*LANES*16
|
||||
assert offset < 16384
|
||||
k.emit(global_load_b128(vdst=v[base_vreg+i*4:base_vreg+i*4+3], addr=v[offset//4096], saddr=s[6:7], offset=offset%4096))
|
||||
k.emit(s_add_u32(s[6], s[6], reg_len * LANES * 4))
|
||||
k.emit(s_addc_u32(s[7], s[7], 0))
|
||||
|
||||
def tree_reduce_to_4567(base_vreg, reg_len):
|
||||
assert reg_len%4 == 0
|
||||
reg_len //= 4
|
||||
while reg_len > 1:
|
||||
half = reg_len // 2
|
||||
for j in range(half):
|
||||
a, b = base_vreg + j*4, base_vreg + (j+half)*4
|
||||
# v[a+0](bank0) += v[b+2](bank2), v[a+1](bank1) += v[b+3](bank3) — src0 and src1 on different banks
|
||||
k.emit(VOPD(VOPDOp.V_DUAL_ADD_F32, VOPDOp.V_DUAL_ADD_F32, vdstx=v[a], vdsty=v[a+1], srcx0=v[a], vsrcx1=v[b+2], srcy0=v[a+1], vsrcy1=v[b+3]))
|
||||
# v[a+2](bank2) += v[b+0](bank0), v[a+3](bank3) += v[b+1](bank1) — src0 and src1 on different banks
|
||||
k.emit(VOPD(VOPDOp.V_DUAL_ADD_F32, VOPDOp.V_DUAL_ADD_F32, vdstx=v[a+2], vdsty=v[a+3], srcx0=v[a+2], vsrcx1=v[b], srcy0=v[a+3], vsrcy1=v[b+1]))
|
||||
reg_len = half
|
||||
k.emit(VOPD(VOPDOp.V_DUAL_ADD_F32, VOPDOp.V_DUAL_ADD_F32, vdstx=v[4], vdsty=v[5], srcx0=v[4], vsrcx1=v[base_vreg], srcy0=v[5], vsrcy1=v[base_vreg+1]))
|
||||
k.emit(VOPD(VOPDOp.V_DUAL_ADD_F32, VOPDOp.V_DUAL_ADD_F32, vdstx=v[6], vdsty=v[7], srcx0=v[6], vsrcx1=v[base_vreg+2], srcy0=v[7], vsrcy1=v[base_vreg+3]))
|
||||
|
||||
BASE_REG = 8
|
||||
LOAD_UNROLL = 64
|
||||
INNER_UNROLL = 2
|
||||
|
||||
assert buf.numel() % (CU_COUNT*LANES*LOAD_UNROLL*INNER_UNROLL) == 0
|
||||
total_batches = buf.numel()//(CU_COUNT*LANES*LOAD_UNROLL*INNER_UNROLL)
|
||||
k.emit(s_mov_b32(s[S_LOOP_CTR], total_batches-1))
|
||||
|
||||
k.label('LOOP')
|
||||
for _ in range(INNER_UNROLL):
|
||||
emit_loads(BASE_REG, reg_len=LOAD_UNROLL)
|
||||
k.waitcnt(vm=0)
|
||||
tree_reduce_to_4567(BASE_REG, reg_len=LOAD_UNROLL)
|
||||
k.emit(s_sub_u32(s[S_LOOP_CTR], s[S_LOOP_CTR], 1))
|
||||
k.emit(s_cbranch_scc0(), target='LOOP')
|
||||
|
||||
# add into v[4]
|
||||
k.emit(v_add_f32_e32(v[4], v[4], v[5]))
|
||||
k.emit(v_add_f32_e32(v[6], v[6], v[7]))
|
||||
k.emit(v_add_f32_e32(v[4], v[4], v[6]))
|
||||
|
||||
# warp shuffle into v[4] on lane 0 using DPP row_shl within each 16-lane row
|
||||
for shift in [1, 2, 4, 8]:
|
||||
k.emit(v_add_f32_e32(v[4], DPP, v[4], vsrc0=v[4], dpp=0x100 | shift, row_mask=0xf, bank_mask=0xf, bc=1))
|
||||
# combine rows: get lane 16's value to lane 0 via permlanex16
|
||||
k.emit(v_permlanex16_b32(v[5], v[4], 0, 0))
|
||||
k.emit(v_add_f32_e32(v[4], v[4], v[5]))
|
||||
|
||||
# atomic store (only on lane 0)
|
||||
k.emit(s_mov_b32(EXEC_LO, 1))
|
||||
k.emit(v_mov_b32_e32(v[0], 0))
|
||||
k.emit(global_atomic_add_f32(addr=v[0], saddr=s[4:5], data=v[4]))
|
||||
|
||||
k.emit(s_sendmsg(simm16=3)) # DEALLOC_VGPRS
|
||||
k.emit(s_endpgm())
|
||||
return k.finalize(UOp.sink(UOp.special(CU_COUNT, 'gidx0'), UOp.special(LANES, 'lidx0'), out, buf, arg=KernelInfo(name="asm_reduce")))
|
||||
|
||||
out = Tensor.zeros(1,).contiguous().realize()
|
||||
eval_harness("RDNA3 assembly kernel", a, lambda x: out.custom_kernel(x, fxn=asm_sum)[0], check=correct)
|
||||
|
||||
if __name__ == "__main__":
|
||||
examples = [int(x) for x in getenv("EXAMPLES", "1,2,3,4,5").split(",")]
|
||||
|
||||
correct = None
|
||||
# First define a Tensor and realize it. We will focus on a 1GB sum kernel on RDNA3
|
||||
a = (Tensor.randn(SZ) if getenv("RAND") else Tensor.ones(SZ)).contiguous().realize()
|
||||
|
||||
if 1 in examples:
|
||||
# *****
|
||||
# This is the high level tinygrad way.
|
||||
# Note that this is split into multiple kernels for speed.
|
||||
correct = eval_harness("basic kernel", a, lambda x: x.sum())
|
||||
|
||||
if 2 in examples:
|
||||
# *****
|
||||
# You can import kernels from CUDA/HIP/Metal.
|
||||
# ChatGPT is great at writing these Kernel
|
||||
example_2_hip(a, correct)
|
||||
|
||||
if 3 in examples:
|
||||
# *****
|
||||
# Now we get to the lower abstraction layers of tinygrad.
|
||||
# You can write a kernel in UOps, and it's 2.5x faster than normal.
|
||||
example_3_custom_uop(a, correct)
|
||||
|
||||
if 4 in examples:
|
||||
# *****
|
||||
# You can also BEAM search stock tinygrad for a faster kernel.
|
||||
# This does even better than all the kernels to date in this simple case.
|
||||
with Context(BEAM=2):
|
||||
eval_harness("BEAMed kernel", a, lambda x: x.sum(), check=correct)
|
||||
|
||||
if 5 in examples:
|
||||
# *****
|
||||
# If you really want to go crazy with speed, you can code in assembly.
|
||||
# There's not too much to gain here over BEAM, but it's a few percent faster.
|
||||
example_5_custom_assembly(a, correct)
|
||||
@@ -0,0 +1,355 @@
|
||||
/*
|
||||
Inspired by https://spec.draculatheme.com/ specification, they should work
|
||||
decently with both dark and light themes.
|
||||
*/
|
||||
:root {
|
||||
--ansi-red: #ff5555;
|
||||
--ansi-green: #50fa7b;
|
||||
--ansi-blue: #265285;
|
||||
--ansi-yellow: #ffb86c;
|
||||
--ansi-magenta: #bd93f9;
|
||||
--ansi-cyan: #8be9fd;
|
||||
--ansi-black: #282a36;
|
||||
--ansi-white: #f8f8f2;
|
||||
}
|
||||
|
||||
.-Color-Green,
|
||||
.-Color-Faint-Green,
|
||||
.-Color-Bold-Green,
|
||||
.-Color-BrightGreen {
|
||||
color: var(--ansi-green);
|
||||
}
|
||||
|
||||
.-Color-Red,
|
||||
.-Color-Faint-Red,
|
||||
.-Color-Bold-Red,
|
||||
.-Color-BrightRed {
|
||||
color: var(--ansi-red);
|
||||
}
|
||||
|
||||
.-Color-Yellow,
|
||||
.-Color-Faint-Yellow,
|
||||
.-Color-Bold-Yellow,
|
||||
.-Color-BrightYellow {
|
||||
color: var(--ansi-yellow);
|
||||
}
|
||||
|
||||
.-Color-Blue,
|
||||
.-Color-Faint-Blue,
|
||||
.-Color-Bold-Blue,
|
||||
.-Color-BrightBlue {
|
||||
color: var(--ansi-blue);
|
||||
}
|
||||
|
||||
.-Color-Magenta,
|
||||
.-Color-Faint-Magenta,
|
||||
.-Color-Bold-Magenta,
|
||||
.-Color-BrightMagenta {
|
||||
color: var(--ansi-magenta);
|
||||
}
|
||||
|
||||
.-Color-Cyan,
|
||||
.-Color-Faint-Cyan,
|
||||
.-Color-Bold-Cyan,
|
||||
.-Color-BrightCyan {
|
||||
color: var(--ansi-cyan);
|
||||
}
|
||||
|
||||
.-Color-White,
|
||||
.-Color-Faint-White,
|
||||
.-Color-Bold-White,
|
||||
.-Color-BrightWhite {
|
||||
color: var(--ansi-white);
|
||||
}
|
||||
|
||||
.-Color-Black,
|
||||
.-Color-Faint-Black,
|
||||
.-Color-Bold-Black,
|
||||
.-Color-BrightBlack {
|
||||
color: var(--ansi-black);
|
||||
}
|
||||
|
||||
.-Color-Faint {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.-Color-Bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.-Color-BGBlack,
|
||||
.-Color-Black-BGBlack,
|
||||
.-Color-Blue-BGBlack,
|
||||
.-Color-Bold-BGBlack,
|
||||
.-Color-BrightBGBlack,
|
||||
.-Color-Bold-Black-BGBlack,
|
||||
.-Color-BrightBlack-BGBlack,
|
||||
.-Color-Bold-Green-BGBlack,
|
||||
.-Color-BrightGreen-BGBlack,
|
||||
.-Color-Bold-Cyan-BGBlack,
|
||||
.-Color-BrightCyan-BGBlack,
|
||||
.-Color-Bold-Blue-BGBlack,
|
||||
.-Color-BrightBlue-BGBlack,
|
||||
.-Color-Bold-Magenta-BGBlack,
|
||||
.-Color-BrightMagenta-BGBlack,
|
||||
.-Color-Bold-Red-BGBlack,
|
||||
.-Color-BrightRed-BGBlack,
|
||||
.-Color-Bold-White-BGBlack,
|
||||
.-Color-BrightWhite-BGBlack,
|
||||
.-Color-Bold-Yellow-BGBlack,
|
||||
.-Color-BrightYellow-BGBlack,
|
||||
.-Color-Cyan-BGBlack,
|
||||
.-Color-Green-BGBlack,
|
||||
.-Color-Magenta-BGBlack,
|
||||
.-Color-Red-BGBlack,
|
||||
.-Color-White-BGBlack,
|
||||
.-Color-Yellow-BGBlack {
|
||||
background-color: var(--ansi-black);
|
||||
}
|
||||
|
||||
.-Color-BGRed,
|
||||
.-Color-Black-BGRed,
|
||||
.-Color-Blue-BGRed,
|
||||
.-Color-Bold-BGRed,
|
||||
.-Color-BrightBGRed,
|
||||
.-Color-Bold-Black-BGRed,
|
||||
.-Color-BrightBlack-BGRed,
|
||||
.-Color-Bold-Green-BGRed,
|
||||
.-Color-BrightGreen-BGRed,
|
||||
.-Color-Bold-Cyan-BGRed,
|
||||
.-Color-BrightCyan-BGRed,
|
||||
.-Color-Bold-Blue-BGRed,
|
||||
.-Color-BrightBlue-BGRed,
|
||||
.-Color-Bold-Magenta-BGRed,
|
||||
.-Color-BrightMagenta-BGRed,
|
||||
.-Color-Bold-Red-BGRed,
|
||||
.-Color-BrightRed-BGRed,
|
||||
.-Color-Bold-White-BGRed,
|
||||
.-Color-BrightWhite-BGRed,
|
||||
.-Color-Bold-Yellow-BGRed,
|
||||
.-Color-BrightYellow-BGRed,
|
||||
.-Color-Cyan-BGRed,
|
||||
.-Color-Green-BGRed,
|
||||
.-Color-Magenta-BGRed,
|
||||
.-Color-Red-BGRed,
|
||||
.-Color-White-BGRed,
|
||||
.-Color-Yellow-BGRed {
|
||||
background-color: var(--ansi-red);
|
||||
}
|
||||
|
||||
.-Color-BGGreen,
|
||||
.-Color-Black-BGGreen,
|
||||
.-Color-Blue-BGGreen,
|
||||
.-Color-Bold-BGGreen,
|
||||
.-Color-BrightBGGreen,
|
||||
.-Color-Bold-Black-BGGreen,
|
||||
.-Color-BrightBlack-BGGreen,
|
||||
.-Color-Bold-Green-BGGreen,
|
||||
.-Color-BrightGreen-BGGreen,
|
||||
.-Color-Bold-Cyan-BGGreen,
|
||||
.-Color-BrightCyan-BGGreen,
|
||||
.-Color-Bold-Blue-BGGreen,
|
||||
.-Color-BrightBlue-BGGreen,
|
||||
.-Color-Bold-Magenta-BGGreen,
|
||||
.-Color-BrightMagenta-BGGreen,
|
||||
.-Color-Bold-Red-BGGreen,
|
||||
.-Color-BrightRed-BGGreen,
|
||||
.-Color-Bold-White-BGGreen,
|
||||
.-Color-BrightWhite-BGGreen,
|
||||
.-Color-Bold-Yellow-BGGreen,
|
||||
.-Color-BrightYellow-BGGreen,
|
||||
.-Color-Cyan-BGGreen,
|
||||
.-Color-Green-BGGreen,
|
||||
.-Color-Magenta-BGGreen,
|
||||
.-Color-Red-BGGreen,
|
||||
.-Color-White-BGGreen,
|
||||
.-Color-Yellow-BGGreen {
|
||||
background-color: var(--ansi-green);
|
||||
}
|
||||
|
||||
.-Color-BGYellow,
|
||||
.-Color-Black-BGYellow,
|
||||
.-Color-Blue-BGYellow,
|
||||
.-Color-Bold-BGYellow,
|
||||
.-Color-BrightBGYellow,
|
||||
.-Color-Bold-Black-BGYellow,
|
||||
.-Color-BrightBlack-BGYellow,
|
||||
.-Color-Bold-Green-BGYellow,
|
||||
.-Color-BrightGreen-BGYellow,
|
||||
.-Color-Bold-Cyan-BGYellow,
|
||||
.-Color-BrightCyan-BGYellow,
|
||||
.-Color-Bold-Blue-BGYellow,
|
||||
.-Color-BrightBlue-BGYellow,
|
||||
.-Color-Bold-Magenta-BGYellow,
|
||||
.-Color-BrightMagenta-BGYellow,
|
||||
.-Color-Bold-Red-BGYellow,
|
||||
.-Color-BrightRed-BGYellow,
|
||||
.-Color-Bold-White-BGYellow,
|
||||
.-Color-BrightWhite-BGYellow,
|
||||
.-Color-Bold-Yellow-BGYellow,
|
||||
.-Color-BrightYellow-BGYellow,
|
||||
.-Color-Cyan-BGYellow,
|
||||
.-Color-Green-BGYellow,
|
||||
.-Color-Magenta-BGYellow,
|
||||
.-Color-Red-BGYellow,
|
||||
.-Color-White-BGYellow,
|
||||
.-Color-Yellow-BGYellow {
|
||||
background-color: var(--ansi-yellow);
|
||||
}
|
||||
|
||||
.-Color-BGBlue,
|
||||
.-Color-Black-BGBlue,
|
||||
.-Color-Blue-BGBlue,
|
||||
.-Color-Bold-BGBlue,
|
||||
.-Color-BrightBGBlue,
|
||||
.-Color-Bold-Black-BGBlue,
|
||||
.-Color-BrightBlack-BGBlue,
|
||||
.-Color-Bold-Green-BGBlue,
|
||||
.-Color-BrightGreen-BGBlue,
|
||||
.-Color-Bold-Cyan-BGBlue,
|
||||
.-Color-BrightCyan-BGBlue,
|
||||
.-Color-Bold-Blue-BGBlue,
|
||||
.-Color-BrightBlue-BGBlue,
|
||||
.-Color-Bold-Magenta-BGBlue,
|
||||
.-Color-BrightMagenta-BGBlue,
|
||||
.-Color-Bold-Red-BGBlue,
|
||||
.-Color-BrightRed-BGBlue,
|
||||
.-Color-Bold-White-BGBlue,
|
||||
.-Color-BrightWhite-BGBlue,
|
||||
.-Color-Bold-Yellow-BGBlue,
|
||||
.-Color-BrightYellow-BGBlue,
|
||||
.-Color-Cyan-BGBlue,
|
||||
.-Color-Green-BGBlue,
|
||||
.-Color-Magenta-BGBlue,
|
||||
.-Color-Red-BGBlue,
|
||||
.-Color-White-BGBlue,
|
||||
.-Color-Yellow-BGBlue {
|
||||
background-color: var(--ansi-blue);
|
||||
}
|
||||
|
||||
.-Color-BGMagenta,
|
||||
.-Color-Black-BGMagenta,
|
||||
.-Color-Blue-BGMagenta,
|
||||
.-Color-Bold-BGMagenta,
|
||||
.-Color-BrightBGMagenta,
|
||||
.-Color-Bold-Black-BGMagenta,
|
||||
.-Color-BrightBlack-BGMagenta,
|
||||
.-Color-Bold-Green-BGMagenta,
|
||||
.-Color-BrightGreen-BGMagenta,
|
||||
.-Color-Bold-Cyan-BGMagenta,
|
||||
.-Color-BrightCyan-BGMagenta,
|
||||
.-Color-Bold-Blue-BGMagenta,
|
||||
.-Color-BrightBlue-BGMagenta,
|
||||
.-Color-Bold-Magenta-BGMagenta,
|
||||
.-Color-BrightMagenta-BGMagenta,
|
||||
.-Color-Bold-Red-BGMagenta,
|
||||
.-Color-BrightRed-BGMagenta,
|
||||
.-Color-Bold-White-BGMagenta,
|
||||
.-Color-BrightWhite-BGMagenta,
|
||||
.-Color-Bold-Yellow-BGMagenta,
|
||||
.-Color-BrightYellow-BGMagenta,
|
||||
.-Color-Cyan-BGMagenta,
|
||||
.-Color-Green-BGMagenta,
|
||||
.-Color-Magenta-BGMagenta,
|
||||
.-Color-Red-BGMagenta,
|
||||
.-Color-White-BGMagenta,
|
||||
.-Color-Yellow-BGMagenta {
|
||||
background-color: var(--ansi-magenta);
|
||||
}
|
||||
|
||||
.-Color-BGCyan,
|
||||
.-Color-Black-BGCyan,
|
||||
.-Color-Blue-BGCyan,
|
||||
.-Color-Bold-BGCyan,
|
||||
.-Color-BrightBGCyan,
|
||||
.-Color-Bold-Black-BGCyan,
|
||||
.-Color-BrightBlack-BGCyan,
|
||||
.-Color-Bold-Green-BGCyan,
|
||||
.-Color-BrightGreen-BGCyan,
|
||||
.-Color-Bold-Cyan-BGCyan,
|
||||
.-Color-BrightCyan-BGCyan,
|
||||
.-Color-Bold-Blue-BGCyan,
|
||||
.-Color-BrightBlue-BGCyan,
|
||||
.-Color-Bold-Magenta-BGCyan,
|
||||
.-Color-BrightMagenta-BGCyan,
|
||||
.-Color-Bold-Red-BGCyan,
|
||||
.-Color-BrightRed-BGCyan,
|
||||
.-Color-Bold-White-BGCyan,
|
||||
.-Color-BrightWhite-BGCyan,
|
||||
.-Color-Bold-Yellow-BGCyan,
|
||||
.-Color-BrightYellow-BGCyan,
|
||||
.-Color-Cyan-BGCyan,
|
||||
.-Color-Green-BGCyan,
|
||||
.-Color-Magenta-BGCyan,
|
||||
.-Color-Red-BGCyan,
|
||||
.-Color-White-BGCyan,
|
||||
.-Color-Yellow-BGCyan {
|
||||
background-color: var(--ansi-cyan);
|
||||
}
|
||||
|
||||
.-Color-BGWhite,
|
||||
.-Color-Black-BGWhite,
|
||||
.-Color-Blue-BGWhite,
|
||||
.-Color-Bold-BGWhite,
|
||||
.-Color-BrightBGWhite,
|
||||
.-Color-Bold-Black-BGWhite,
|
||||
.-Color-BrightBlack-BGWhite,
|
||||
.-Color-Bold-Green-BGWhite,
|
||||
.-Color-BrightGreen-BGWhite,
|
||||
.-Color-Bold-Cyan-BGWhite,
|
||||
.-Color-BrightCyan-BGWhite,
|
||||
.-Color-Bold-Blue-BGWhite,
|
||||
.-Color-BrightBlue-BGWhite,
|
||||
.-Color-Bold-Magenta-BGWhite,
|
||||
.-Color-BrightMagenta-BGWhite,
|
||||
.-Color-Bold-Red-BGWhite,
|
||||
.-Color-BrightRed-BGWhite,
|
||||
.-Color-Bold-White-BGWhite,
|
||||
.-Color-BrightWhite-BGWhite,
|
||||
.-Color-Bold-Yellow-BGWhite,
|
||||
.-Color-BrightYellow-BGWhite,
|
||||
.-Color-Cyan-BGWhite,
|
||||
.-Color-Green-BGWhite,
|
||||
.-Color-Magenta-BGWhite,
|
||||
.-Color-Red-BGWhite,
|
||||
.-Color-White-BGWhite,
|
||||
.-Color-Yellow-BGWhite {
|
||||
background-color: var(--ansi-white);
|
||||
}
|
||||
|
||||
.-Color-Black,
|
||||
.-Color-Bold-Black,
|
||||
.-Color-BrightBlack,
|
||||
.-Color-Black-BGBlack,
|
||||
.-Color-Bold-Black-BGBlack,
|
||||
.-Color-BrightBlack-BGBlack,
|
||||
.-Color-Black-BGGreen,
|
||||
.-Color-Red-BGRed,
|
||||
.-Color-Bold-Red-BGRed,
|
||||
.-Color-BrightRed-BGRed,
|
||||
.-Color-Bold-Blue-BGBlue,
|
||||
.-Color-BrightBlue-BGBlue,
|
||||
.-Color-Blue-BGBlue {
|
||||
text-shadow: 0 0 1px var(--ansi-white);
|
||||
}
|
||||
|
||||
.-Color-Bold-Cyan-BGCyan,
|
||||
.-Color-BrightCyan-BGCyan,
|
||||
.-Color-Bold-Magenta-BGMagenta,
|
||||
.-Color-BrightMagenta-BGMagenta,
|
||||
.-Color-Bold-White,
|
||||
.-Color-BrightWhite,
|
||||
.-Color-Bold-Yellow-BGYellow,
|
||||
.-Color-BrightYellow-BGYellow,
|
||||
.-Color-Bold-Green-BGGreen,
|
||||
.-Color-BrightGreen-BGGreen,
|
||||
.-Color-Cyan-BGCyan,
|
||||
.-Color-Cyan-BGGreen,
|
||||
.-Color-Green-BGCyan,
|
||||
.-Color-Green-BGGreen,
|
||||
.-Color-Magenta-BGMagenta,
|
||||
.-Color-White,
|
||||
.-Color-White-BGWhite,
|
||||
.-Color-Yellow-BGYellow {
|
||||
text-shadow: 0 0 1px var(--ansi-black);
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
html[data-theme="light"] {
|
||||
@import "https://cdn.jsdelivr.net/npm/highlightjs-themes@1.0.0/tomorrow.css"
|
||||
}
|
||||
|
||||
html[data-theme="dark"] {
|
||||
@import "https://cdn.jsdelivr.net/npm/highlightjs-themes@1.0.0/tomorrow-night-blue.min.css"
|
||||
}
|
||||
|
||||
|
||||
.ace_gutter {
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.pyodide-editor {
|
||||
width: 100%;
|
||||
font-size: .85em;
|
||||
}
|
||||
|
||||
.pyodide-editor-bar {
|
||||
color: var(--md-primary-bg-color);
|
||||
background-color: var(--md-primary-fg-color);
|
||||
width: 100%;
|
||||
font: monospace;
|
||||
font-size: 0.75em;
|
||||
padding: 2px 0 2px;
|
||||
}
|
||||
|
||||
.pyodide-bar-item {
|
||||
padding: 0 18px 0;
|
||||
display: inline-block;
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.pyodide pre {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.pyodide-output {
|
||||
width: 100%;
|
||||
margin-bottom: -15px;
|
||||
min-height: 46px;
|
||||
max-height: 400px
|
||||
}
|
||||
|
||||
.pyodide-clickable {
|
||||
cursor: pointer;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
/* For themes other than Material. */
|
||||
.pyodide .twemoji svg {
|
||||
width: 1rem;
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
var _sessions = {};
|
||||
|
||||
function getSession(name, pyodide) {
|
||||
if (!(name in _sessions)) {
|
||||
_sessions[name] = pyodide.globals.get("dict")();
|
||||
}
|
||||
return _sessions[name];
|
||||
}
|
||||
|
||||
function writeOutput(element, string) {
|
||||
element.innerHTML += string + '\n';
|
||||
}
|
||||
|
||||
function clearOutput(element) {
|
||||
element.innerHTML = '';
|
||||
}
|
||||
|
||||
async function evaluatePython(pyodide, editor, output, session) {
|
||||
pyodide.setStdout({ batched: (string) => { writeOutput(output, new Option(string).innerHTML); } });
|
||||
let result, code = editor.getValue();
|
||||
clearOutput(output);
|
||||
try {
|
||||
result = await pyodide.runPythonAsync(code, { globals: getSession(session, pyodide) });
|
||||
} catch (error) {
|
||||
writeOutput(output, new Option(error.toString()).innerHTML);
|
||||
}
|
||||
if (result) writeOutput(output, new Option(result).innerHTML);
|
||||
hljs.highlightElement(output);
|
||||
}
|
||||
|
||||
async function initPyodide() {
|
||||
try {
|
||||
let pyodide = await loadPyodide();
|
||||
await pyodide.loadPackage("micropip");
|
||||
return pyodide;
|
||||
} catch(error) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function getTheme() {
|
||||
return document.body.getAttribute('data-md-color-scheme');
|
||||
}
|
||||
|
||||
function setTheme(editor, currentTheme, light, dark) {
|
||||
// https://gist.github.com/RyanNutt/cb8d60997d97905f0b2aea6c3b5c8ee0
|
||||
if (currentTheme === "default") {
|
||||
editor.setTheme("ace/theme/" + light);
|
||||
document.querySelector(`link[title="light"]`).removeAttribute("disabled");
|
||||
document.querySelector(`link[title="dark"]`).setAttribute("disabled", "disabled");
|
||||
} else if (currentTheme === "slate") {
|
||||
editor.setTheme("ace/theme/" + dark);
|
||||
document.querySelector(`link[title="dark"]`).removeAttribute("disabled");
|
||||
document.querySelector(`link[title="light"]`).setAttribute("disabled", "disabled");
|
||||
}
|
||||
}
|
||||
|
||||
function updateTheme(editor, light, dark) {
|
||||
// Create a new MutationObserver instance
|
||||
const observer = new MutationObserver((mutations) => {
|
||||
// Loop through the mutations that occurred
|
||||
mutations.forEach((mutation) => {
|
||||
// Check if the mutation was a change to the data-md-color-scheme attribute
|
||||
if (mutation.attributeName === 'data-md-color-scheme') {
|
||||
// Get the new value of the attribute
|
||||
const newColorScheme = mutation.target.getAttribute('data-md-color-scheme');
|
||||
// Update the editor theme
|
||||
setTheme(editor, newColorScheme, light, dark);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Configure the observer to watch for changes to the data-md-color-scheme attribute
|
||||
observer.observe(document.body, {
|
||||
attributes: true,
|
||||
attributeFilter: ['data-md-color-scheme'],
|
||||
});
|
||||
}
|
||||
|
||||
async function setupPyodide(
|
||||
idPrefix,
|
||||
install = null,
|
||||
themeLight = 'tomorrow',
|
||||
themeDark = 'tomorrow_night',
|
||||
session = null,
|
||||
minLines = 5,
|
||||
maxLines = 30,
|
||||
) {
|
||||
const editor = ace.edit(idPrefix + "editor");
|
||||
const run = document.getElementById(idPrefix + "run");
|
||||
const clear = document.getElementById(idPrefix + "clear");
|
||||
const output = document.getElementById(idPrefix + "output");
|
||||
|
||||
updateTheme(editor, themeLight, themeDark);
|
||||
|
||||
editor.session.setMode("ace/mode/python");
|
||||
setTheme(editor, getTheme(), themeLight, themeDark);
|
||||
|
||||
editor.setOption("minLines", minLines);
|
||||
editor.setOption("maxLines", maxLines);
|
||||
|
||||
// Force editor to resize after setting options
|
||||
editor.resize();
|
||||
|
||||
writeOutput(output, "Initializing...");
|
||||
let pyodide = await pyodidePromise;
|
||||
if (install && install.length) {
|
||||
try {
|
||||
micropip = pyodide.pyimport("micropip");
|
||||
for (const package of install)
|
||||
await micropip.install(package);
|
||||
clearOutput(output);
|
||||
} catch (error) {
|
||||
clearOutput(output);
|
||||
writeOutput(output, `Could not install one or more packages: ${install.join(", ")}\n`);
|
||||
writeOutput(output, new Option(error.toString()).innerHTML);
|
||||
}
|
||||
} else {
|
||||
clearOutput(output);
|
||||
}
|
||||
run.onclick = () => evaluatePython(pyodide, editor, output, session);
|
||||
clear.onclick = () => clearOutput(output);
|
||||
output.parentElement.parentElement.addEventListener("keydown", (event) => {
|
||||
if (event.ctrlKey && event.key.toLowerCase() === 'enter') {
|
||||
event.preventDefault();
|
||||
run.click();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var pyodidePromise = initPyodide();
|
||||
@@ -0,0 +1,237 @@
|
||||
|
||||
/* Avoid breaking parameter names, etc. in table cells. */
|
||||
.doc-contents td code {
|
||||
word-break: normal !important;
|
||||
}
|
||||
|
||||
/* No line break before first paragraph of descriptions. */
|
||||
.doc-md-description,
|
||||
.doc-md-description>p:first-child {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
/* No text transformation from Material for MkDocs for H5 headings. */
|
||||
.md-typeset h5 .doc-object-name {
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
/* Max width for docstring sections tables. */
|
||||
.doc .md-typeset__table,
|
||||
.doc .md-typeset__table table {
|
||||
display: table !important;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.doc .md-typeset__table tr {
|
||||
display: table-row;
|
||||
}
|
||||
|
||||
/* Defaults in Spacy table style. */
|
||||
.doc-param-default,
|
||||
.doc-type_param-default {
|
||||
float: right;
|
||||
}
|
||||
|
||||
/* Parameter headings must be inline, not blocks. */
|
||||
.doc-heading-parameter,
|
||||
.doc-heading-type_parameter {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
/* Default font size for parameter headings. */
|
||||
.md-typeset .doc-heading-parameter {
|
||||
font-size: inherit;
|
||||
}
|
||||
|
||||
/* Prefer space on the right, not the left of parameter permalinks. */
|
||||
.doc-heading-parameter .headerlink,
|
||||
.doc-heading-type_parameter .headerlink {
|
||||
margin-left: 0 !important;
|
||||
margin-right: 0.2rem;
|
||||
}
|
||||
|
||||
/* Backward-compatibility: docstring section titles in bold. */
|
||||
.doc-section-title {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* Backlinks crumb separator. */
|
||||
.doc-backlink-crumb {
|
||||
display: inline-flex;
|
||||
gap: .2rem;
|
||||
white-space: nowrap;
|
||||
align-items: center;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.doc-backlink-crumb:not(:first-child)::before {
|
||||
background-color: var(--md-default-fg-color--lighter);
|
||||
content: "";
|
||||
display: inline;
|
||||
height: 1rem;
|
||||
--md-path-icon: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M8.59 16.58 13.17 12 8.59 7.41 10 6l6 6-6 6z"/></svg>');
|
||||
-webkit-mask-image: var(--md-path-icon);
|
||||
mask-image: var(--md-path-icon);
|
||||
width: 1rem;
|
||||
}
|
||||
.doc-backlink-crumb.last {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* Symbols in Navigation and ToC. */
|
||||
:root, :host,
|
||||
[data-md-color-scheme="default"] {
|
||||
--doc-symbol-parameter-fg-color: #df50af;
|
||||
--doc-symbol-type_parameter-fg-color: #df50af;
|
||||
--doc-symbol-attribute-fg-color: #953800;
|
||||
--doc-symbol-function-fg-color: #8250df;
|
||||
--doc-symbol-method-fg-color: #8250df;
|
||||
--doc-symbol-class-fg-color: #0550ae;
|
||||
--doc-symbol-type_alias-fg-color: #0550ae;
|
||||
--doc-symbol-module-fg-color: #5cad0f;
|
||||
|
||||
--doc-symbol-parameter-bg-color: #df50af1a;
|
||||
--doc-symbol-type_parameter-bg-color: #df50af1a;
|
||||
--doc-symbol-attribute-bg-color: #9538001a;
|
||||
--doc-symbol-function-bg-color: #8250df1a;
|
||||
--doc-symbol-method-bg-color: #8250df1a;
|
||||
--doc-symbol-class-bg-color: #0550ae1a;
|
||||
--doc-symbol-type_alias-bg-color: #0550ae1a;
|
||||
--doc-symbol-module-bg-color: #5cad0f1a;
|
||||
}
|
||||
|
||||
[data-md-color-scheme="slate"] {
|
||||
--doc-symbol-parameter-fg-color: #ffa8cc;
|
||||
--doc-symbol-type_parameter-fg-color: #ffa8cc;
|
||||
--doc-symbol-attribute-fg-color: #ffa657;
|
||||
--doc-symbol-function-fg-color: #d2a8ff;
|
||||
--doc-symbol-method-fg-color: #d2a8ff;
|
||||
--doc-symbol-class-fg-color: #79c0ff;
|
||||
--doc-symbol-type_alias-fg-color: #79c0ff;
|
||||
--doc-symbol-module-fg-color: #baff79;
|
||||
|
||||
--doc-symbol-parameter-bg-color: #ffa8cc1a;
|
||||
--doc-symbol-type_parameter-bg-color: #ffa8cc1a;
|
||||
--doc-symbol-attribute-bg-color: #ffa6571a;
|
||||
--doc-symbol-function-bg-color: #d2a8ff1a;
|
||||
--doc-symbol-method-bg-color: #d2a8ff1a;
|
||||
--doc-symbol-class-bg-color: #79c0ff1a;
|
||||
--doc-symbol-type_alias-bg-color: #79c0ff1a;
|
||||
--doc-symbol-module-bg-color: #baff791a;
|
||||
}
|
||||
|
||||
code.doc-symbol {
|
||||
border-radius: .1rem;
|
||||
font-size: .85em;
|
||||
padding: 0 .3em;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
code.doc-symbol-parameter,
|
||||
a code.doc-symbol-parameter {
|
||||
color: var(--doc-symbol-parameter-fg-color);
|
||||
background-color: var(--doc-symbol-parameter-bg-color);
|
||||
}
|
||||
|
||||
code.doc-symbol-parameter::after {
|
||||
content: "param";
|
||||
}
|
||||
|
||||
code.doc-symbol-type_parameter,
|
||||
a code.doc-symbol-type_parameter {
|
||||
color: var(--doc-symbol-type_parameter-fg-color);
|
||||
background-color: var(--doc-symbol-type_parameter-bg-color);
|
||||
}
|
||||
|
||||
code.doc-symbol-type_parameter::after {
|
||||
content: "type-param";
|
||||
}
|
||||
|
||||
code.doc-symbol-attribute,
|
||||
a code.doc-symbol-attribute {
|
||||
color: var(--doc-symbol-attribute-fg-color);
|
||||
background-color: var(--doc-symbol-attribute-bg-color);
|
||||
}
|
||||
|
||||
code.doc-symbol-attribute::after {
|
||||
content: "attr";
|
||||
}
|
||||
|
||||
code.doc-symbol-function,
|
||||
a code.doc-symbol-function {
|
||||
color: var(--doc-symbol-function-fg-color);
|
||||
background-color: var(--doc-symbol-function-bg-color);
|
||||
}
|
||||
|
||||
code.doc-symbol-function::after {
|
||||
content: "func";
|
||||
}
|
||||
|
||||
code.doc-symbol-method,
|
||||
a code.doc-symbol-method {
|
||||
color: var(--doc-symbol-method-fg-color);
|
||||
background-color: var(--doc-symbol-method-bg-color);
|
||||
}
|
||||
|
||||
code.doc-symbol-method::after {
|
||||
content: "meth";
|
||||
}
|
||||
|
||||
code.doc-symbol-class,
|
||||
a code.doc-symbol-class {
|
||||
color: var(--doc-symbol-class-fg-color);
|
||||
background-color: var(--doc-symbol-class-bg-color);
|
||||
}
|
||||
|
||||
code.doc-symbol-class::after {
|
||||
content: "class";
|
||||
}
|
||||
|
||||
|
||||
code.doc-symbol-type_alias,
|
||||
a code.doc-symbol-type_alias {
|
||||
color: var(--doc-symbol-type_alias-fg-color);
|
||||
background-color: var(--doc-symbol-type_alias-bg-color);
|
||||
}
|
||||
|
||||
code.doc-symbol-type_alias::after {
|
||||
content: "type";
|
||||
}
|
||||
|
||||
code.doc-symbol-module,
|
||||
a code.doc-symbol-module {
|
||||
color: var(--doc-symbol-module-fg-color);
|
||||
background-color: var(--doc-symbol-module-bg-color);
|
||||
}
|
||||
|
||||
code.doc-symbol-module::after {
|
||||
content: "mod";
|
||||
}
|
||||
|
||||
.doc-signature .autorefs {
|
||||
color: inherit;
|
||||
border-bottom: 1px dotted currentcolor;
|
||||
}
|
||||
|
||||
/* Source code blocks (admonitions). */
|
||||
:root {
|
||||
--md-admonition-icon--mkdocstrings-source: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M15.22 4.97a.75.75 0 0 1 1.06 0l6.5 6.5a.75.75 0 0 1 0 1.06l-6.5 6.5a.749.749 0 0 1-1.275-.326.75.75 0 0 1 .215-.734L21.19 12l-5.97-5.97a.75.75 0 0 1 0-1.06m-6.44 0a.75.75 0 0 1 0 1.06L2.81 12l5.97 5.97a.749.749 0 0 1-.326 1.275.75.75 0 0 1-.734-.215l-6.5-6.5a.75.75 0 0 1 0-1.06l6.5-6.5a.75.75 0 0 1 1.06 0"/></svg>')
|
||||
}
|
||||
.md-typeset .admonition.mkdocstrings-source,
|
||||
.md-typeset details.mkdocstrings-source {
|
||||
border: none;
|
||||
padding: 0;
|
||||
}
|
||||
.md-typeset .admonition.mkdocstrings-source:focus-within,
|
||||
.md-typeset details.mkdocstrings-source:focus-within {
|
||||
box-shadow: none;
|
||||
}
|
||||
.md-typeset .mkdocstrings-source > .admonition-title,
|
||||
.md-typeset .mkdocstrings-source > summary {
|
||||
background-color: inherit;
|
||||
}
|
||||
.md-typeset .mkdocstrings-source > .admonition-title::before,
|
||||
.md-typeset .mkdocstrings-source > summary::before {
|
||||
background-color: var(--md-default-fg-color);
|
||||
-webkit-mask-image: var(--md-admonition-icon--mkdocstrings-source);
|
||||
mask-image: var(--md-admonition-icon--mkdocstrings-source);
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.8 KiB |
+16
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+18
@@ -0,0 +1,18 @@
|
||||
/*!
|
||||
* Lunr languages, `Danish` language
|
||||
* https://github.com/MihaiValentin/lunr-languages
|
||||
*
|
||||
* Copyright 2014, Mihai Valentin
|
||||
* http://www.mozilla.org/MPL/
|
||||
*/
|
||||
/*!
|
||||
* based on
|
||||
* Snowball JavaScript Library v0.3
|
||||
* http://code.google.com/p/urim/
|
||||
* http://snowball.tartarus.org/
|
||||
*
|
||||
* Copyright 2010, Oleg Mazko
|
||||
* http://www.mozilla.org/MPL/
|
||||
*/
|
||||
|
||||
!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.da=function(){this.pipeline.reset(),this.pipeline.add(e.da.trimmer,e.da.stopWordFilter,e.da.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.da.stemmer))},e.da.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.da.trimmer=e.trimmerSupport.generateTrimmer(e.da.wordCharacters),e.Pipeline.registerFunction(e.da.trimmer,"trimmer-da"),e.da.stemmer=function(){var r=e.stemmerSupport.Among,i=e.stemmerSupport.SnowballProgram,n=new function(){function e(){var e,r=f.cursor+3;if(d=f.limit,0<=r&&r<=f.limit){for(a=r;;){if(e=f.cursor,f.in_grouping(w,97,248)){f.cursor=e;break}if(f.cursor=e,e>=f.limit)return;f.cursor++}for(;!f.out_grouping(w,97,248);){if(f.cursor>=f.limit)return;f.cursor++}d=f.cursor,d<a&&(d=a)}}function n(){var e,r;if(f.cursor>=d&&(r=f.limit_backward,f.limit_backward=d,f.ket=f.cursor,e=f.find_among_b(c,32),f.limit_backward=r,e))switch(f.bra=f.cursor,e){case 1:f.slice_del();break;case 2:f.in_grouping_b(p,97,229)&&f.slice_del()}}function t(){var e,r=f.limit-f.cursor;f.cursor>=d&&(e=f.limit_backward,f.limit_backward=d,f.ket=f.cursor,f.find_among_b(l,4)?(f.bra=f.cursor,f.limit_backward=e,f.cursor=f.limit-r,f.cursor>f.limit_backward&&(f.cursor--,f.bra=f.cursor,f.slice_del())):f.limit_backward=e)}function s(){var e,r,i,n=f.limit-f.cursor;if(f.ket=f.cursor,f.eq_s_b(2,"st")&&(f.bra=f.cursor,f.eq_s_b(2,"ig")&&f.slice_del()),f.cursor=f.limit-n,f.cursor>=d&&(r=f.limit_backward,f.limit_backward=d,f.ket=f.cursor,e=f.find_among_b(m,5),f.limit_backward=r,e))switch(f.bra=f.cursor,e){case 1:f.slice_del(),i=f.limit-f.cursor,t(),f.cursor=f.limit-i;break;case 2:f.slice_from("løs")}}function o(){var e;f.cursor>=d&&(e=f.limit_backward,f.limit_backward=d,f.ket=f.cursor,f.out_grouping_b(w,97,248)?(f.bra=f.cursor,u=f.slice_to(u),f.limit_backward=e,f.eq_v_b(u)&&f.slice_del()):f.limit_backward=e)}var a,d,u,c=[new r("hed",-1,1),new r("ethed",0,1),new r("ered",-1,1),new r("e",-1,1),new r("erede",3,1),new r("ende",3,1),new r("erende",5,1),new r("ene",3,1),new r("erne",3,1),new r("ere",3,1),new r("en",-1,1),new r("heden",10,1),new r("eren",10,1),new r("er",-1,1),new r("heder",13,1),new r("erer",13,1),new r("s",-1,2),new r("heds",16,1),new r("es",16,1),new r("endes",18,1),new r("erendes",19,1),new r("enes",18,1),new r("ernes",18,1),new r("eres",18,1),new r("ens",16,1),new r("hedens",24,1),new r("erens",24,1),new r("ers",16,1),new r("ets",16,1),new r("erets",28,1),new r("et",-1,1),new r("eret",30,1)],l=[new r("gd",-1,-1),new r("dt",-1,-1),new r("gt",-1,-1),new r("kt",-1,-1)],m=[new r("ig",-1,1),new r("lig",0,1),new r("elig",1,1),new r("els",-1,1),new r("løst",-1,2)],w=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,48,0,128],p=[239,254,42,3,0,0,0,0,0,0,0,0,0,0,0,0,16],f=new i;this.setCurrent=function(e){f.setCurrent(e)},this.getCurrent=function(){return f.getCurrent()},this.stem=function(){var r=f.cursor;return e(),f.limit_backward=r,f.cursor=f.limit,n(),f.cursor=f.limit,t(),f.cursor=f.limit,s(),f.cursor=f.limit,o(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return n.setCurrent(e),n.stem(),n.getCurrent()}):(n.setCurrent(e),n.stem(),n.getCurrent())}}(),e.Pipeline.registerFunction(e.da.stemmer,"stemmer-da"),e.da.stopWordFilter=e.generateStopWordFilter("ad af alle alt anden at blev blive bliver da de dem den denne der deres det dette dig din disse dog du efter eller en end er et for fra ham han hans har havde have hende hendes her hos hun hvad hvis hvor i ikke ind jeg jer jo kunne man mange med meget men mig min mine mit mod ned noget nogle nu når og også om op os over på selv sig sin sine sit skal skulle som sådan thi til ud under var vi vil ville vor være været".split(" ")),e.Pipeline.registerFunction(e.da.stopWordFilter,"stopWordFilter-da")}});
|
||||
+18
File diff suppressed because one or more lines are too long
+18
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+18
File diff suppressed because one or more lines are too long
+18
File diff suppressed because one or more lines are too long
+18
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+1
@@ -0,0 +1 @@
|
||||
!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.hi=function(){this.pipeline.reset(),this.pipeline.add(e.hi.trimmer,e.hi.stopWordFilter,e.hi.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.hi.stemmer))},e.hi.wordCharacters="ऀ-ःऄ-एऐ-टठ-यर-िी-ॏॐ-य़ॠ-९॰-ॿa-zA-Za-zA-Z0-90-9",e.hi.trimmer=e.trimmerSupport.generateTrimmer(e.hi.wordCharacters),e.Pipeline.registerFunction(e.hi.trimmer,"trimmer-hi"),e.hi.stopWordFilter=e.generateStopWordFilter("अत अपना अपनी अपने अभी अंदर आदि आप इत्यादि इन इनका इन्हीं इन्हें इन्हों इस इसका इसकी इसके इसमें इसी इसे उन उनका उनकी उनके उनको उन्हीं उन्हें उन्हों उस उसके उसी उसे एक एवं एस ऐसे और कई कर करता करते करना करने करें कहते कहा का काफ़ी कि कितना किन्हें किन्हों किया किर किस किसी किसे की कुछ कुल के को कोई कौन कौनसा गया घर जब जहाँ जा जितना जिन जिन्हें जिन्हों जिस जिसे जीधर जैसा जैसे जो तक तब तरह तिन तिन्हें तिन्हों तिस तिसे तो था थी थे दबारा दिया दुसरा दूसरे दो द्वारा न नके नहीं ना निहायत नीचे ने पर पहले पूरा पे फिर बनी बही बहुत बाद बाला बिलकुल भी भीतर मगर मानो मे में यदि यह यहाँ यही या यिह ये रखें रहा रहे ऱ्वासा लिए लिये लेकिन व वग़ैरह वर्ग वह वहाँ वहीं वाले वुह वे वो सकता सकते सबसे सभी साथ साबुत साभ सारा से सो संग ही हुआ हुई हुए है हैं हो होता होती होते होना होने".split(" ")),e.hi.stemmer=function(){return function(e){return"function"==typeof e.update?e.update(function(e){return e}):e}}();var r=e.wordcut;r.init(),e.hi.tokenizer=function(i){if(!arguments.length||null==i||void 0==i)return[];if(Array.isArray(i))return i.map(function(r){return isLunr2?new e.Token(r.toLowerCase()):r.toLowerCase()});var t=i.toString().toLowerCase().replace(/^\s+/,"");return r.cut(t).split("|")},e.Pipeline.registerFunction(e.hi.stemmer,"stemmer-hi"),e.Pipeline.registerFunction(e.hi.stopWordFilter,"stopWordFilter-hi")}});
|
||||
+18
File diff suppressed because one or more lines are too long
+1
@@ -0,0 +1 @@
|
||||
!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.hy=function(){this.pipeline.reset(),this.pipeline.add(e.hy.trimmer,e.hy.stopWordFilter)},e.hy.wordCharacters="[A-Za-z-֏ff-ﭏ]",e.hy.trimmer=e.trimmerSupport.generateTrimmer(e.hy.wordCharacters),e.Pipeline.registerFunction(e.hy.trimmer,"trimmer-hy"),e.hy.stopWordFilter=e.generateStopWordFilter("դու և եք էիր էիք հետո նաև նրանք որը վրա է որ պիտի են այս մեջ ն իր ու ի այդ որոնք այն կամ էր մի ես համար այլ իսկ էին ենք հետ ին թ էինք մենք նրա նա դուք եմ էի ըստ որպես ում".split(" ")),e.Pipeline.registerFunction(e.hy.stopWordFilter,"stopWordFilter-hy"),e.hy.stemmer=function(){return function(e){return"function"==typeof e.update?e.update(function(e){return e}):e}}(),e.Pipeline.registerFunction(e.hy.stemmer,"stemmer-hy")}});
|
||||
+18
File diff suppressed because one or more lines are too long
+1
@@ -0,0 +1 @@
|
||||
!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var r="2"==e.version[0];e.ja=function(){this.pipeline.reset(),this.pipeline.add(e.ja.trimmer,e.ja.stopWordFilter,e.ja.stemmer),r?this.tokenizer=e.ja.tokenizer:(e.tokenizer&&(e.tokenizer=e.ja.tokenizer),this.tokenizerFn&&(this.tokenizerFn=e.ja.tokenizer))};var t=new e.TinySegmenter;e.ja.tokenizer=function(i){var n,o,s,p,a,u,m,l,c,f;if(!arguments.length||null==i||void 0==i)return[];if(Array.isArray(i))return i.map(function(t){return r?new e.Token(t.toLowerCase()):t.toLowerCase()});for(o=i.toString().toLowerCase().replace(/^\s+/,""),n=o.length-1;n>=0;n--)if(/\S/.test(o.charAt(n))){o=o.substring(0,n+1);break}for(a=[],s=o.length,c=0,l=0;c<=s;c++)if(u=o.charAt(c),m=c-l,u.match(/\s/)||c==s){if(m>0)for(p=t.segment(o.slice(l,c)).filter(function(e){return!!e}),f=l,n=0;n<p.length;n++)r?a.push(new e.Token(p[n],{position:[f,p[n].length],index:a.length})):a.push(p[n]),f+=p[n].length;l=c+1}return a},e.ja.stemmer=function(){return function(e){return e}}(),e.Pipeline.registerFunction(e.ja.stemmer,"stemmer-ja"),e.ja.wordCharacters="一二三四五六七八九十百千万億兆一-龠々〆ヵヶぁ-んァ-ヴーア-ン゙a-zA-Za-zA-Z0-90-9",e.ja.trimmer=e.trimmerSupport.generateTrimmer(e.ja.wordCharacters),e.Pipeline.registerFunction(e.ja.trimmer,"trimmer-ja"),e.ja.stopWordFilter=e.generateStopWordFilter("これ それ あれ この その あの ここ そこ あそこ こちら どこ だれ なに なん 何 私 貴方 貴方方 我々 私達 あの人 あのかた 彼女 彼 です あります おります います は が の に を で え から まで より も どの と し それで しかし".split(" ")),e.Pipeline.registerFunction(e.ja.stopWordFilter,"stopWordFilter-ja"),e.jp=e.ja,e.Pipeline.registerFunction(e.jp.stemmer,"stemmer-jp"),e.Pipeline.registerFunction(e.jp.trimmer,"trimmer-jp"),e.Pipeline.registerFunction(e.jp.stopWordFilter,"stopWordFilter-jp")}});
|
||||
+1
@@ -0,0 +1 @@
|
||||
module.exports=require("./lunr.ja");
|
||||
+1
@@ -0,0 +1 @@
|
||||
!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.kn=function(){this.pipeline.reset(),this.pipeline.add(e.kn.trimmer,e.kn.stopWordFilter,e.kn.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.kn.stemmer))},e.kn.wordCharacters="ಀ-಄ಅ-ಔಕ-ಹಾ-ೌ಼-ಽೕ-ೖೝ-ೞೠ-ೡೢ-ೣ೦-೯ೱ-ೳ",e.kn.trimmer=e.trimmerSupport.generateTrimmer(e.kn.wordCharacters),e.Pipeline.registerFunction(e.kn.trimmer,"trimmer-kn"),e.kn.stopWordFilter=e.generateStopWordFilter("ಮತ್ತು ಈ ಒಂದು ರಲ್ಲಿ ಹಾಗೂ ಎಂದು ಅಥವಾ ಇದು ರ ಅವರು ಎಂಬ ಮೇಲೆ ಅವರ ತನ್ನ ಆದರೆ ತಮ್ಮ ನಂತರ ಮೂಲಕ ಹೆಚ್ಚು ನ ಆ ಕೆಲವು ಅನೇಕ ಎರಡು ಹಾಗು ಪ್ರಮುಖ ಇದನ್ನು ಇದರ ಸುಮಾರು ಅದರ ಅದು ಮೊದಲ ಬಗ್ಗೆ ನಲ್ಲಿ ರಂದು ಇತರ ಅತ್ಯಂತ ಹೆಚ್ಚಿನ ಸಹ ಸಾಮಾನ್ಯವಾಗಿ ನೇ ಹಲವಾರು ಹೊಸ ದಿ ಕಡಿಮೆ ಯಾವುದೇ ಹೊಂದಿದೆ ದೊಡ್ಡ ಅನ್ನು ಇವರು ಪ್ರಕಾರ ಇದೆ ಮಾತ್ರ ಕೂಡ ಇಲ್ಲಿ ಎಲ್ಲಾ ವಿವಿಧ ಅದನ್ನು ಹಲವು ರಿಂದ ಕೇವಲ ದ ದಕ್ಷಿಣ ಗೆ ಅವನ ಅತಿ ನೆಯ ಬಹಳ ಕೆಲಸ ಎಲ್ಲ ಪ್ರತಿ ಇತ್ಯಾದಿ ಇವು ಬೇರೆ ಹೀಗೆ ನಡುವೆ ಇದಕ್ಕೆ ಎಸ್ ಇವರ ಮೊದಲು ಶ್ರೀ ಮಾಡುವ ಇದರಲ್ಲಿ ರೀತಿಯ ಮಾಡಿದ ಕಾಲ ಅಲ್ಲಿ ಮಾಡಲು ಅದೇ ಈಗ ಅವು ಗಳು ಎ ಎಂಬುದು ಅವನು ಅಂದರೆ ಅವರಿಗೆ ಇರುವ ವಿಶೇಷ ಮುಂದೆ ಅವುಗಳ ಮುಂತಾದ ಮೂಲ ಬಿ ಮೀ ಒಂದೇ ಇನ್ನೂ ಹೆಚ್ಚಾಗಿ ಮಾಡಿ ಅವರನ್ನು ಇದೇ ಯ ರೀತಿಯಲ್ಲಿ ಜೊತೆ ಅದರಲ್ಲಿ ಮಾಡಿದರು ನಡೆದ ಆಗ ಮತ್ತೆ ಪೂರ್ವ ಆತ ಬಂದ ಯಾವ ಒಟ್ಟು ಇತರೆ ಹಿಂದೆ ಪ್ರಮಾಣದ ಗಳನ್ನು ಕುರಿತು ಯು ಆದ್ದರಿಂದ ಅಲ್ಲದೆ ನಗರದ ಮೇಲಿನ ಏಕೆಂದರೆ ರಷ್ಟು ಎಂಬುದನ್ನು ಬಾರಿ ಎಂದರೆ ಹಿಂದಿನ ಆದರೂ ಆದ ಸಂಬಂಧಿಸಿದ ಮತ್ತೊಂದು ಸಿ ಆತನ ".split(" ")),e.kn.stemmer=function(){return function(e){return"function"==typeof e.update?e.update(function(e){return e}):e}}();var r=e.wordcut;r.init(),e.kn.tokenizer=function(t){if(!arguments.length||null==t||void 0==t)return[];if(Array.isArray(t))return t.map(function(r){return isLunr2?new e.Token(r.toLowerCase()):r.toLowerCase()});var n=t.toString().toLowerCase().replace(/^\s+/,"");return r.cut(n).split("|")},e.Pipeline.registerFunction(e.kn.stemmer,"stemmer-kn"),e.Pipeline.registerFunction(e.kn.stopWordFilter,"stopWordFilter-kn")}});
|
||||
+1
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
!function(e,t){"function"==typeof define&&define.amd?define(t):"object"==typeof exports?module.exports=t():t()(e.lunr)}(this,function(){return function(e){e.multiLanguage=function(){for(var t=Array.prototype.slice.call(arguments),i=t.join("-"),r="",n=[],s=[],p=0;p<t.length;++p)"en"==t[p]?(r+="\\w",n.unshift(e.stopWordFilter),n.push(e.stemmer),s.push(e.stemmer)):(r+=e[t[p]].wordCharacters,e[t[p]].stopWordFilter&&n.unshift(e[t[p]].stopWordFilter),e[t[p]].stemmer&&(n.push(e[t[p]].stemmer),s.push(e[t[p]].stemmer)));var o=e.trimmerSupport.generateTrimmer(r);return e.Pipeline.registerFunction(o,"lunr-multi-trimmer-"+i),n.unshift(o),function(){this.pipeline.reset(),this.pipeline.add.apply(this.pipeline,n),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add.apply(this.searchPipeline,s))}}}});
|
||||
+18
File diff suppressed because one or more lines are too long
+18
@@ -0,0 +1,18 @@
|
||||
/*!
|
||||
* Lunr languages, `Norwegian` language
|
||||
* https://github.com/MihaiValentin/lunr-languages
|
||||
*
|
||||
* Copyright 2014, Mihai Valentin
|
||||
* http://www.mozilla.org/MPL/
|
||||
*/
|
||||
/*!
|
||||
* based on
|
||||
* Snowball JavaScript Library v0.3
|
||||
* http://code.google.com/p/urim/
|
||||
* http://snowball.tartarus.org/
|
||||
*
|
||||
* Copyright 2010, Oleg Mazko
|
||||
* http://www.mozilla.org/MPL/
|
||||
*/
|
||||
|
||||
!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.no=function(){this.pipeline.reset(),this.pipeline.add(e.no.trimmer,e.no.stopWordFilter,e.no.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.no.stemmer))},e.no.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.no.trimmer=e.trimmerSupport.generateTrimmer(e.no.wordCharacters),e.Pipeline.registerFunction(e.no.trimmer,"trimmer-no"),e.no.stemmer=function(){var r=e.stemmerSupport.Among,n=e.stemmerSupport.SnowballProgram,i=new function(){function e(){var e,r=w.cursor+3;if(a=w.limit,0<=r||r<=w.limit){for(s=r;;){if(e=w.cursor,w.in_grouping(d,97,248)){w.cursor=e;break}if(e>=w.limit)return;w.cursor=e+1}for(;!w.out_grouping(d,97,248);){if(w.cursor>=w.limit)return;w.cursor++}a=w.cursor,a<s&&(a=s)}}function i(){var e,r,n;if(w.cursor>=a&&(r=w.limit_backward,w.limit_backward=a,w.ket=w.cursor,e=w.find_among_b(m,29),w.limit_backward=r,e))switch(w.bra=w.cursor,e){case 1:w.slice_del();break;case 2:n=w.limit-w.cursor,w.in_grouping_b(c,98,122)?w.slice_del():(w.cursor=w.limit-n,w.eq_s_b(1,"k")&&w.out_grouping_b(d,97,248)&&w.slice_del());break;case 3:w.slice_from("er")}}function t(){var e,r=w.limit-w.cursor;w.cursor>=a&&(e=w.limit_backward,w.limit_backward=a,w.ket=w.cursor,w.find_among_b(u,2)?(w.bra=w.cursor,w.limit_backward=e,w.cursor=w.limit-r,w.cursor>w.limit_backward&&(w.cursor--,w.bra=w.cursor,w.slice_del())):w.limit_backward=e)}function o(){var e,r;w.cursor>=a&&(r=w.limit_backward,w.limit_backward=a,w.ket=w.cursor,e=w.find_among_b(l,11),e?(w.bra=w.cursor,w.limit_backward=r,1==e&&w.slice_del()):w.limit_backward=r)}var s,a,m=[new r("a",-1,1),new r("e",-1,1),new r("ede",1,1),new r("ande",1,1),new r("ende",1,1),new r("ane",1,1),new r("ene",1,1),new r("hetene",6,1),new r("erte",1,3),new r("en",-1,1),new r("heten",9,1),new r("ar",-1,1),new r("er",-1,1),new r("heter",12,1),new r("s",-1,2),new r("as",14,1),new r("es",14,1),new r("edes",16,1),new r("endes",16,1),new r("enes",16,1),new r("hetenes",19,1),new r("ens",14,1),new r("hetens",21,1),new r("ers",14,1),new r("ets",14,1),new r("et",-1,1),new r("het",25,1),new r("ert",-1,3),new r("ast",-1,1)],u=[new r("dt",-1,-1),new r("vt",-1,-1)],l=[new r("leg",-1,1),new r("eleg",0,1),new r("ig",-1,1),new r("eig",2,1),new r("lig",2,1),new r("elig",4,1),new r("els",-1,1),new r("lov",-1,1),new r("elov",7,1),new r("slov",7,1),new r("hetslov",9,1)],d=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,48,0,128],c=[119,125,149,1],w=new n;this.setCurrent=function(e){w.setCurrent(e)},this.getCurrent=function(){return w.getCurrent()},this.stem=function(){var r=w.cursor;return e(),w.limit_backward=r,w.cursor=w.limit,i(),w.cursor=w.limit,t(),w.cursor=w.limit,o(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return i.setCurrent(e),i.stem(),i.getCurrent()}):(i.setCurrent(e),i.stem(),i.getCurrent())}}(),e.Pipeline.registerFunction(e.no.stemmer,"stemmer-no"),e.no.stopWordFilter=e.generateStopWordFilter("alle at av bare begge ble blei bli blir blitt både båe da de deg dei deim deira deires dem den denne der dere deres det dette di din disse ditt du dykk dykkar då eg ein eit eitt eller elles en enn er et ett etter for fordi fra før ha hadde han hans har hennar henne hennes her hjå ho hoe honom hoss hossen hun hva hvem hver hvilke hvilken hvis hvor hvordan hvorfor i ikke ikkje ikkje ingen ingi inkje inn inni ja jeg kan kom korleis korso kun kunne kva kvar kvarhelst kven kvi kvifor man mange me med medan meg meget mellom men mi min mine mitt mot mykje ned no noe noen noka noko nokon nokor nokre nå når og også om opp oss over på samme seg selv si si sia sidan siden sin sine sitt sjøl skal skulle slik so som som somme somt så sånn til um upp ut uten var vart varte ved vere verte vi vil ville vore vors vort vår være være vært å".split(" ")),e.Pipeline.registerFunction(e.no.stopWordFilter,"stopWordFilter-no")}});
|
||||
+18
File diff suppressed because one or more lines are too long
+18
File diff suppressed because one or more lines are too long
+18
File diff suppressed because one or more lines are too long
+1
@@ -0,0 +1 @@
|
||||
!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.sa=function(){this.pipeline.reset(),this.pipeline.add(e.sa.trimmer,e.sa.stopWordFilter,e.sa.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.sa.stemmer))},e.sa.wordCharacters="ऀ-ःऄ-एऐ-टठ-यर-िी-ॏॐ-य़ॠ-९॰-ॿ꣠-꣱ꣲ-ꣷ꣸-ꣻ꣼-ꣽꣾ-ꣿᆰ0-ᆰ9",e.sa.trimmer=e.trimmerSupport.generateTrimmer(e.sa.wordCharacters),e.Pipeline.registerFunction(e.sa.trimmer,"trimmer-sa"),e.sa.stopWordFilter=e.generateStopWordFilter('तथा अयम् एकम् इत्यस्मिन् तथा तत् वा अयम् इत्यस्य ते आहूत उपरि तेषाम् किन्तु तेषाम् तदा इत्यनेन अधिकः इत्यस्य तत् केचन बहवः द्वि तथा महत्वपूर्णः अयम् अस्य विषये अयं अस्ति तत् प्रथमः विषये इत्युपरि इत्युपरि इतर अधिकतमः अधिकः अपि सामान्यतया ठ इतरेतर नूतनम् द न्यूनम् कश्चित् वा विशालः द सः अस्ति तदनुसारम् तत्र अस्ति केवलम् अपि अत्र सर्वे विविधाः तत् बहवः यतः इदानीम् द दक्षिण इत्यस्मै तस्य उपरि नथ अतीव कार्यम् सर्वे एकैकम् इत्यादि। एते सन्ति उत इत्थम् मध्ये एतदर्थं . स कस्य प्रथमः श्री. करोति अस्मिन् प्रकारः निर्मिता कालः तत्र कर्तुं समान अधुना ते सन्ति स एकः अस्ति सः अर्थात् तेषां कृते . स्थितम् विशेषः अग्रिम तेषाम् समान स्रोतः ख म समान इदानीमपि अधिकतया करोतु ते समान इत्यस्य वीथी सह यस्मिन् कृतवान् धृतः तदा पुनः पूर्वं सः आगतः किम् कुल इतर पुरा मात्रा स विषये उ अतएव अपि नगरस्य उपरि यतः प्रतिशतं कतरः कालः साधनानि भूत तथापि जात सम्बन्धि अन्यत् ग अतः अस्माकं स्वकीयाः अस्माकं इदानीं अन्तः इत्यादयः भवन्तः इत्यादयः एते एताः तस्य अस्य इदम् एते तेषां तेषां तेषां तान् तेषां तेषां तेषां समानः सः एकः च तादृशाः बहवः अन्ये च वदन्ति यत् कियत् कस्मै कस्मै यस्मै यस्मै यस्मै यस्मै न अतिनीचः किन्तु प्रथमं सम्पूर्णतया ततः चिरकालानन्तरं पुस्तकं सम्पूर्णतया अन्तः किन्तु अत्र वा इह इव श्रद्धाय अवशिष्यते परन्तु अन्ये वर्गाः सन्ति ते सन्ति शक्नुवन्ति सर्वे मिलित्वा सर्वे एकत्र"'.split(" ")),e.sa.stemmer=function(){return function(e){return"function"==typeof e.update?e.update(function(e){return e}):e}}();var r=e.wordcut;r.init(),e.sa.tokenizer=function(t){if(!arguments.length||null==t||void 0==t)return[];if(Array.isArray(t))return t.map(function(r){return isLunr2?new e.Token(r.toLowerCase()):r.toLowerCase()});var i=t.toString().toLowerCase().replace(/^\s+/,"");return r.cut(i).split("|")},e.Pipeline.registerFunction(e.sa.stemmer,"stemmer-sa"),e.Pipeline.registerFunction(e.sa.stopWordFilter,"stopWordFilter-sa")}});
|
||||
@@ -0,0 +1 @@
|
||||
!function(r,t){"function"==typeof define&&define.amd?define(t):"object"==typeof exports?module.exports=t():t()(r.lunr)}(this,function(){return function(r){r.stemmerSupport={Among:function(r,t,i,s){if(this.toCharArray=function(r){for(var t=r.length,i=new Array(t),s=0;s<t;s++)i[s]=r.charCodeAt(s);return i},!r&&""!=r||!t&&0!=t||!i)throw"Bad Among initialisation: s:"+r+", substring_i: "+t+", result: "+i;this.s_size=r.length,this.s=this.toCharArray(r),this.substring_i=t,this.result=i,this.method=s},SnowballProgram:function(){var r;return{bra:0,ket:0,limit:0,cursor:0,limit_backward:0,setCurrent:function(t){r=t,this.cursor=0,this.limit=t.length,this.limit_backward=0,this.bra=this.cursor,this.ket=this.limit},getCurrent:function(){var t=r;return r=null,t},in_grouping:function(t,i,s){if(this.cursor<this.limit){var e=r.charCodeAt(this.cursor);if(e<=s&&e>=i&&(e-=i,t[e>>3]&1<<(7&e)))return this.cursor++,!0}return!1},in_grouping_b:function(t,i,s){if(this.cursor>this.limit_backward){var e=r.charCodeAt(this.cursor-1);if(e<=s&&e>=i&&(e-=i,t[e>>3]&1<<(7&e)))return this.cursor--,!0}return!1},out_grouping:function(t,i,s){if(this.cursor<this.limit){var e=r.charCodeAt(this.cursor);if(e>s||e<i)return this.cursor++,!0;if(e-=i,!(t[e>>3]&1<<(7&e)))return this.cursor++,!0}return!1},out_grouping_b:function(t,i,s){if(this.cursor>this.limit_backward){var e=r.charCodeAt(this.cursor-1);if(e>s||e<i)return this.cursor--,!0;if(e-=i,!(t[e>>3]&1<<(7&e)))return this.cursor--,!0}return!1},eq_s:function(t,i){if(this.limit-this.cursor<t)return!1;for(var s=0;s<t;s++)if(r.charCodeAt(this.cursor+s)!=i.charCodeAt(s))return!1;return this.cursor+=t,!0},eq_s_b:function(t,i){if(this.cursor-this.limit_backward<t)return!1;for(var s=0;s<t;s++)if(r.charCodeAt(this.cursor-t+s)!=i.charCodeAt(s))return!1;return this.cursor-=t,!0},find_among:function(t,i){for(var s=0,e=i,n=this.cursor,u=this.limit,o=0,h=0,c=!1;;){for(var a=s+(e-s>>1),f=0,l=o<h?o:h,_=t[a],m=l;m<_.s_size;m++){if(n+l==u){f=-1;break}if(f=r.charCodeAt(n+l)-_.s[m])break;l++}if(f<0?(e=a,h=l):(s=a,o=l),e-s<=1){if(s>0||e==s||c)break;c=!0}}for(;;){var _=t[s];if(o>=_.s_size){if(this.cursor=n+_.s_size,!_.method)return _.result;var b=_.method();if(this.cursor=n+_.s_size,b)return _.result}if((s=_.substring_i)<0)return 0}},find_among_b:function(t,i){for(var s=0,e=i,n=this.cursor,u=this.limit_backward,o=0,h=0,c=!1;;){for(var a=s+(e-s>>1),f=0,l=o<h?o:h,_=t[a],m=_.s_size-1-l;m>=0;m--){if(n-l==u){f=-1;break}if(f=r.charCodeAt(n-1-l)-_.s[m])break;l++}if(f<0?(e=a,h=l):(s=a,o=l),e-s<=1){if(s>0||e==s||c)break;c=!0}}for(;;){var _=t[s];if(o>=_.s_size){if(this.cursor=n-_.s_size,!_.method)return _.result;var b=_.method();if(this.cursor=n-_.s_size,b)return _.result}if((s=_.substring_i)<0)return 0}},replace_s:function(t,i,s){var e=s.length-(i-t),n=r.substring(0,t),u=r.substring(i);return r=n+s+u,this.limit+=e,this.cursor>=i?this.cursor+=e:this.cursor>t&&(this.cursor=t),e},slice_check:function(){if(this.bra<0||this.bra>this.ket||this.ket>this.limit||this.limit>r.length)throw"faulty slice operation"},slice_from:function(r){this.slice_check(),this.replace_s(this.bra,this.ket,r)},slice_del:function(){this.slice_from("")},insert:function(r,t,i){var s=this.replace_s(r,t,i);r<=this.bra&&(this.bra+=s),r<=this.ket&&(this.ket+=s)},slice_to:function(){return this.slice_check(),r.substring(this.bra,this.ket)},eq_v_b:function(r){return this.eq_s_b(r.length,r)}}}},r.trimmerSupport={generateTrimmer:function(r){var t=new RegExp("^[^"+r+"]+"),i=new RegExp("[^"+r+"]+$");return function(r){return"function"==typeof r.update?r.update(function(r){return r.replace(t,"").replace(i,"")}):r.replace(t,"").replace(i,"")}}}}});
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
/*!
|
||||
* Lunr languages, `Swedish` language
|
||||
* https://github.com/MihaiValentin/lunr-languages
|
||||
*
|
||||
* Copyright 2014, Mihai Valentin
|
||||
* http://www.mozilla.org/MPL/
|
||||
*/
|
||||
/*!
|
||||
* based on
|
||||
* Snowball JavaScript Library v0.3
|
||||
* http://code.google.com/p/urim/
|
||||
* http://snowball.tartarus.org/
|
||||
*
|
||||
* Copyright 2010, Oleg Mazko
|
||||
* http://www.mozilla.org/MPL/
|
||||
*/
|
||||
|
||||
!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.sv=function(){this.pipeline.reset(),this.pipeline.add(e.sv.trimmer,e.sv.stopWordFilter,e.sv.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.sv.stemmer))},e.sv.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.sv.trimmer=e.trimmerSupport.generateTrimmer(e.sv.wordCharacters),e.Pipeline.registerFunction(e.sv.trimmer,"trimmer-sv"),e.sv.stemmer=function(){var r=e.stemmerSupport.Among,n=e.stemmerSupport.SnowballProgram,t=new function(){function e(){var e,r=w.cursor+3;if(o=w.limit,0<=r||r<=w.limit){for(a=r;;){if(e=w.cursor,w.in_grouping(l,97,246)){w.cursor=e;break}if(w.cursor=e,w.cursor>=w.limit)return;w.cursor++}for(;!w.out_grouping(l,97,246);){if(w.cursor>=w.limit)return;w.cursor++}o=w.cursor,o<a&&(o=a)}}function t(){var e,r=w.limit_backward;if(w.cursor>=o&&(w.limit_backward=o,w.cursor=w.limit,w.ket=w.cursor,e=w.find_among_b(u,37),w.limit_backward=r,e))switch(w.bra=w.cursor,e){case 1:w.slice_del();break;case 2:w.in_grouping_b(d,98,121)&&w.slice_del()}}function i(){var e=w.limit_backward;w.cursor>=o&&(w.limit_backward=o,w.cursor=w.limit,w.find_among_b(c,7)&&(w.cursor=w.limit,w.ket=w.cursor,w.cursor>w.limit_backward&&(w.bra=--w.cursor,w.slice_del())),w.limit_backward=e)}function s(){var e,r;if(w.cursor>=o){if(r=w.limit_backward,w.limit_backward=o,w.cursor=w.limit,w.ket=w.cursor,e=w.find_among_b(m,5))switch(w.bra=w.cursor,e){case 1:w.slice_del();break;case 2:w.slice_from("lös");break;case 3:w.slice_from("full")}w.limit_backward=r}}var a,o,u=[new r("a",-1,1),new r("arna",0,1),new r("erna",0,1),new r("heterna",2,1),new r("orna",0,1),new r("ad",-1,1),new r("e",-1,1),new r("ade",6,1),new r("ande",6,1),new r("arne",6,1),new r("are",6,1),new r("aste",6,1),new r("en",-1,1),new r("anden",12,1),new r("aren",12,1),new r("heten",12,1),new r("ern",-1,1),new r("ar",-1,1),new r("er",-1,1),new r("heter",18,1),new r("or",-1,1),new r("s",-1,2),new r("as",21,1),new r("arnas",22,1),new r("ernas",22,1),new r("ornas",22,1),new r("es",21,1),new r("ades",26,1),new r("andes",26,1),new r("ens",21,1),new r("arens",29,1),new r("hetens",29,1),new r("erns",21,1),new r("at",-1,1),new r("andet",-1,1),new r("het",-1,1),new r("ast",-1,1)],c=[new r("dd",-1,-1),new r("gd",-1,-1),new r("nn",-1,-1),new r("dt",-1,-1),new r("gt",-1,-1),new r("kt",-1,-1),new r("tt",-1,-1)],m=[new r("ig",-1,1),new r("lig",0,1),new r("els",-1,1),new r("fullt",-1,3),new r("löst",-1,2)],l=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,24,0,32],d=[119,127,149],w=new n;this.setCurrent=function(e){w.setCurrent(e)},this.getCurrent=function(){return w.getCurrent()},this.stem=function(){var r=w.cursor;return e(),w.limit_backward=r,w.cursor=w.limit,t(),w.cursor=w.limit,i(),w.cursor=w.limit,s(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return t.setCurrent(e),t.stem(),t.getCurrent()}):(t.setCurrent(e),t.stem(),t.getCurrent())}}(),e.Pipeline.registerFunction(e.sv.stemmer,"stemmer-sv"),e.sv.stopWordFilter=e.generateStopWordFilter("alla allt att av blev bli blir blivit de dem den denna deras dess dessa det detta dig din dina ditt du där då efter ej eller en er era ert ett från för ha hade han hans har henne hennes hon honom hur här i icke ingen inom inte jag ju kan kunde man med mellan men mig min mina mitt mot mycket ni nu när någon något några och om oss på samma sedan sig sin sina sitta själv skulle som så sådan sådana sådant till under upp ut utan vad var vara varför varit varje vars vart vem vi vid vilka vilkas vilken vilket vår våra vårt än är åt över".split(" ")),e.Pipeline.registerFunction(e.sv.stopWordFilter,"stopWordFilter-sv")}});
|
||||
+1
@@ -0,0 +1 @@
|
||||
!function(e,t){"function"==typeof define&&define.amd?define(t):"object"==typeof exports?module.exports=t():t()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.ta=function(){this.pipeline.reset(),this.pipeline.add(e.ta.trimmer,e.ta.stopWordFilter,e.ta.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.ta.stemmer))},e.ta.wordCharacters="-உஊ-ஏஐ-ஙச-ட-னப-யர-ஹ-ிீ-ொ-ௐ---௩௪-௯௰-௹௺-a-zA-Za-zA-Z0-90-9",e.ta.trimmer=e.trimmerSupport.generateTrimmer(e.ta.wordCharacters),e.Pipeline.registerFunction(e.ta.trimmer,"trimmer-ta"),e.ta.stopWordFilter=e.generateStopWordFilter("அங்கு அங்கே அது அதை அந்த அவர் அவர்கள் அவள் அவன் அவை ஆக ஆகவே ஆகையால் ஆதலால் ஆதலினால் ஆனாலும் ஆனால் இங்கு இங்கே இது இதை இந்த இப்படி இவர் இவர்கள் இவள் இவன் இவை இவ்வளவு உனக்கு உனது உன் உன்னால் எங்கு எங்கே எது எதை எந்த எப்படி எவர் எவர்கள் எவள் எவன் எவை எவ்வளவு எனக்கு எனது எனவே என் என்ன என்னால் ஏது ஏன் தனது தன்னால் தானே தான் நாங்கள் நாம் நான் நீ நீங்கள்".split(" ")),e.ta.stemmer=function(){return function(e){return"function"==typeof e.update?e.update(function(e){return e}):e}}();var t=e.wordcut;t.init(),e.ta.tokenizer=function(r){if(!arguments.length||null==r||void 0==r)return[];if(Array.isArray(r))return r.map(function(t){return isLunr2?new e.Token(t.toLowerCase()):t.toLowerCase()});var i=r.toString().toLowerCase().replace(/^\s+/,"");return t.cut(i).split("|")},e.Pipeline.registerFunction(e.ta.stemmer,"stemmer-ta"),e.Pipeline.registerFunction(e.ta.stopWordFilter,"stopWordFilter-ta")}});
|
||||
+1
@@ -0,0 +1 @@
|
||||
!function(e,t){"function"==typeof define&&define.amd?define(t):"object"==typeof exports?module.exports=t():t()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.te=function(){this.pipeline.reset(),this.pipeline.add(e.te.trimmer,e.te.stopWordFilter,e.te.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.te.stemmer))},e.te.wordCharacters="ఀ-ఄఅ-ఔక-హా-ౌౕ-ౖౘ-ౚౠ-ౡౢ-ౣ౦-౯౸-౿఼ఽ్ౝ౷",e.te.trimmer=e.trimmerSupport.generateTrimmer(e.te.wordCharacters),e.Pipeline.registerFunction(e.te.trimmer,"trimmer-te"),e.te.stopWordFilter=e.generateStopWordFilter("అందరూ అందుబాటులో అడగండి అడగడం అడ్డంగా అనుగుణంగా అనుమతించు అనుమతిస్తుంది అయితే ఇప్పటికే ఉన్నారు ఎక్కడైనా ఎప్పుడు ఎవరైనా ఎవరో ఏ ఏదైనా ఏమైనప్పటికి ఒక ఒకరు కనిపిస్తాయి కాదు కూడా గా గురించి చుట్టూ చేయగలిగింది తగిన తర్వాత దాదాపు దూరంగా నిజంగా పై ప్రకారం ప్రక్కన మధ్య మరియు మరొక మళ్ళీ మాత్రమే మెచ్చుకో వద్ద వెంట వేరుగా వ్యతిరేకంగా సంబంధం".split(" ")),e.te.stemmer=function(){return function(e){return"function"==typeof e.update?e.update(function(e){return e}):e}}();var t=e.wordcut;t.init(),e.te.tokenizer=function(r){if(!arguments.length||null==r||void 0==r)return[];if(Array.isArray(r))return r.map(function(t){return isLunr2?new e.Token(t.toLowerCase()):t.toLowerCase()});var i=r.toString().toLowerCase().replace(/^\s+/,"");return t.cut(i).split("|")},e.Pipeline.registerFunction(e.te.stemmer,"stemmer-te"),e.Pipeline.registerFunction(e.te.stopWordFilter,"stopWordFilter-te")}});
|
||||
+1
@@ -0,0 +1 @@
|
||||
!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var r="2"==e.version[0];e.th=function(){this.pipeline.reset(),this.pipeline.add(e.th.trimmer),r?this.tokenizer=e.th.tokenizer:(e.tokenizer&&(e.tokenizer=e.th.tokenizer),this.tokenizerFn&&(this.tokenizerFn=e.th.tokenizer))},e.th.wordCharacters="[-]",e.th.trimmer=e.trimmerSupport.generateTrimmer(e.th.wordCharacters),e.Pipeline.registerFunction(e.th.trimmer,"trimmer-th");var t=e.wordcut;t.init(),e.th.tokenizer=function(i){if(!arguments.length||null==i||void 0==i)return[];if(Array.isArray(i))return i.map(function(t){return r?new e.Token(t):t});var n=i.toString().replace(/^\s+/,"");return t.cut(n).split("|")}}});
|
||||
+18
File diff suppressed because one or more lines are too long
+1
@@ -0,0 +1 @@
|
||||
!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.vi=function(){this.pipeline.reset(),this.pipeline.add(e.vi.stopWordFilter,e.vi.trimmer)},e.vi.wordCharacters="[A-Za-ẓ̀͐́͑̉̃̓ÂâÊêÔôĂ-ăĐ-đƠ-ơƯ-ư]",e.vi.trimmer=e.trimmerSupport.generateTrimmer(e.vi.wordCharacters),e.Pipeline.registerFunction(e.vi.trimmer,"trimmer-vi"),e.vi.stopWordFilter=e.generateStopWordFilter("là cái nhưng mà".split(" "))}});
|
||||
+1
@@ -0,0 +1 @@
|
||||
!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r(require("@node-rs/jieba")):r()(e.lunr)}(this,function(e){return function(r,t){if(void 0===r)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===r.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var i="2"==r.version[0];r.zh=function(){this.pipeline.reset(),this.pipeline.add(r.zh.trimmer,r.zh.stopWordFilter,r.zh.stemmer),i?this.tokenizer=r.zh.tokenizer:(r.tokenizer&&(r.tokenizer=r.zh.tokenizer),this.tokenizerFn&&(this.tokenizerFn=r.zh.tokenizer))},r.zh.tokenizer=function(n){if(!arguments.length||null==n||void 0==n)return[];if(Array.isArray(n))return n.map(function(e){return i?new r.Token(e.toLowerCase()):e.toLowerCase()});t&&e.load(t);var o=n.toString().trim().toLowerCase(),s=[];e.cut(o,!0).forEach(function(e){s=s.concat(e.split(" "))}),s=s.filter(function(e){return!!e});var u=0;return s.map(function(e,t){if(i){var n=o.indexOf(e,u),s={};return s.position=[n,e.length],s.index=t,u=n,new r.Token(e,s)}return e})},r.zh.wordCharacters="\\w一-龥",r.zh.trimmer=r.trimmerSupport.generateTrimmer(r.zh.wordCharacters),r.Pipeline.registerFunction(r.zh.trimmer,"trimmer-zh"),r.zh.stemmer=function(){return function(e){return e}}(),r.Pipeline.registerFunction(r.zh.stemmer,"stemmer-zh"),r.zh.stopWordFilter=r.generateStopWordFilter("的 一 不 在 人 有 是 为 為 以 于 於 上 他 而 后 後 之 来 來 及 了 因 下 可 到 由 这 這 与 與 也 此 但 并 並 个 個 其 已 无 無 小 我 们 們 起 最 再 今 去 好 只 又 或 很 亦 某 把 那 你 乃 它 吧 被 比 别 趁 当 當 从 從 得 打 凡 儿 兒 尔 爾 该 該 各 给 給 跟 和 何 还 還 即 几 幾 既 看 据 據 距 靠 啦 另 么 麽 每 嘛 拿 哪 您 凭 憑 且 却 卻 让 讓 仍 啥 如 若 使 谁 誰 虽 雖 随 隨 同 所 她 哇 嗡 往 些 向 沿 哟 喲 用 咱 则 則 怎 曾 至 致 着 著 诸 諸 自".split(" ")),r.Pipeline.registerFunction(r.zh.stopWordFilter,"stopWordFilter-zh")}});
|
||||
@@ -0,0 +1,206 @@
|
||||
/**
|
||||
* export the module via AMD, CommonJS or as a browser global
|
||||
* Export code from https://github.com/umdjs/umd/blob/master/returnExports.js
|
||||
*/
|
||||
;(function (root, factory) {
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
// AMD. Register as an anonymous module.
|
||||
define(factory)
|
||||
} else if (typeof exports === 'object') {
|
||||
/**
|
||||
* Node. Does not work with strict CommonJS, but
|
||||
* only CommonJS-like environments that support module.exports,
|
||||
* like Node.
|
||||
*/
|
||||
module.exports = factory()
|
||||
} else {
|
||||
// Browser globals (root is window)
|
||||
factory()(root.lunr);
|
||||
}
|
||||
}(this, function () {
|
||||
/**
|
||||
* Just return a value to define the module export.
|
||||
* This example returns an object, but the module
|
||||
* can return a function as the exported value.
|
||||
*/
|
||||
|
||||
return function(lunr) {
|
||||
// TinySegmenter 0.1 -- Super compact Japanese tokenizer in Javascript
|
||||
// (c) 2008 Taku Kudo <[email protected]>
|
||||
// TinySegmenter is freely distributable under the terms of a new BSD licence.
|
||||
// For details, see http://chasen.org/~taku/software/TinySegmenter/LICENCE.txt
|
||||
|
||||
function TinySegmenter() {
|
||||
var patterns = {
|
||||
"[一二三四五六七八九十百千万億兆]":"M",
|
||||
"[一-龠々〆ヵヶ]":"H",
|
||||
"[ぁ-ん]":"I",
|
||||
"[ァ-ヴーア-ン゙ー]":"K",
|
||||
"[a-zA-Za-zA-Z]":"A",
|
||||
"[0-90-9]":"N"
|
||||
}
|
||||
this.chartype_ = [];
|
||||
for (var i in patterns) {
|
||||
var regexp = new RegExp(i);
|
||||
this.chartype_.push([regexp, patterns[i]]);
|
||||
}
|
||||
|
||||
this.BIAS__ = -332
|
||||
this.BC1__ = {"HH":6,"II":2461,"KH":406,"OH":-1378};
|
||||
this.BC2__ = {"AA":-3267,"AI":2744,"AN":-878,"HH":-4070,"HM":-1711,"HN":4012,"HO":3761,"IA":1327,"IH":-1184,"II":-1332,"IK":1721,"IO":5492,"KI":3831,"KK":-8741,"MH":-3132,"MK":3334,"OO":-2920};
|
||||
this.BC3__ = {"HH":996,"HI":626,"HK":-721,"HN":-1307,"HO":-836,"IH":-301,"KK":2762,"MK":1079,"MM":4034,"OA":-1652,"OH":266};
|
||||
this.BP1__ = {"BB":295,"OB":304,"OO":-125,"UB":352};
|
||||
this.BP2__ = {"BO":60,"OO":-1762};
|
||||
this.BQ1__ = {"BHH":1150,"BHM":1521,"BII":-1158,"BIM":886,"BMH":1208,"BNH":449,"BOH":-91,"BOO":-2597,"OHI":451,"OIH":-296,"OKA":1851,"OKH":-1020,"OKK":904,"OOO":2965};
|
||||
this.BQ2__ = {"BHH":118,"BHI":-1159,"BHM":466,"BIH":-919,"BKK":-1720,"BKO":864,"OHH":-1139,"OHM":-181,"OIH":153,"UHI":-1146};
|
||||
this.BQ3__ = {"BHH":-792,"BHI":2664,"BII":-299,"BKI":419,"BMH":937,"BMM":8335,"BNN":998,"BOH":775,"OHH":2174,"OHM":439,"OII":280,"OKH":1798,"OKI":-793,"OKO":-2242,"OMH":-2402,"OOO":11699};
|
||||
this.BQ4__ = {"BHH":-3895,"BIH":3761,"BII":-4654,"BIK":1348,"BKK":-1806,"BMI":-3385,"BOO":-12396,"OAH":926,"OHH":266,"OHK":-2036,"ONN":-973};
|
||||
this.BW1__ = {",と":660,",同":727,"B1あ":1404,"B1同":542,"、と":660,"、同":727,"」と":1682,"あっ":1505,"いう":1743,"いっ":-2055,"いる":672,"うし":-4817,"うん":665,"から":3472,"がら":600,"こう":-790,"こと":2083,"こん":-1262,"さら":-4143,"さん":4573,"した":2641,"して":1104,"すで":-3399,"そこ":1977,"それ":-871,"たち":1122,"ため":601,"った":3463,"つい":-802,"てい":805,"てき":1249,"でき":1127,"です":3445,"では":844,"とい":-4915,"とみ":1922,"どこ":3887,"ない":5713,"なっ":3015,"など":7379,"なん":-1113,"にし":2468,"には":1498,"にも":1671,"に対":-912,"の一":-501,"の中":741,"ませ":2448,"まで":1711,"まま":2600,"まる":-2155,"やむ":-1947,"よっ":-2565,"れた":2369,"れで":-913,"をし":1860,"を見":731,"亡く":-1886,"京都":2558,"取り":-2784,"大き":-2604,"大阪":1497,"平方":-2314,"引き":-1336,"日本":-195,"本当":-2423,"毎日":-2113,"目指":-724,"B1あ":1404,"B1同":542,"」と":1682};
|
||||
this.BW2__ = {"..":-11822,"11":-669,"――":-5730,"−−":-13175,"いう":-1609,"うか":2490,"かし":-1350,"かも":-602,"から":-7194,"かれ":4612,"がい":853,"がら":-3198,"きた":1941,"くな":-1597,"こと":-8392,"この":-4193,"させ":4533,"され":13168,"さん":-3977,"しい":-1819,"しか":-545,"した":5078,"して":972,"しな":939,"その":-3744,"たい":-1253,"たた":-662,"ただ":-3857,"たち":-786,"たと":1224,"たは":-939,"った":4589,"って":1647,"っと":-2094,"てい":6144,"てき":3640,"てく":2551,"ては":-3110,"ても":-3065,"でい":2666,"でき":-1528,"でし":-3828,"です":-4761,"でも":-4203,"とい":1890,"とこ":-1746,"とと":-2279,"との":720,"とみ":5168,"とも":-3941,"ない":-2488,"なが":-1313,"など":-6509,"なの":2614,"なん":3099,"にお":-1615,"にし":2748,"にな":2454,"によ":-7236,"に対":-14943,"に従":-4688,"に関":-11388,"のか":2093,"ので":-7059,"のに":-6041,"のの":-6125,"はい":1073,"はが":-1033,"はず":-2532,"ばれ":1813,"まし":-1316,"まで":-6621,"まれ":5409,"めて":-3153,"もい":2230,"もの":-10713,"らか":-944,"らし":-1611,"らに":-1897,"りし":651,"りま":1620,"れた":4270,"れて":849,"れば":4114,"ろう":6067,"われ":7901,"を通":-11877,"んだ":728,"んな":-4115,"一人":602,"一方":-1375,"一日":970,"一部":-1051,"上が":-4479,"会社":-1116,"出て":2163,"分の":-7758,"同党":970,"同日":-913,"大阪":-2471,"委員":-1250,"少な":-1050,"年度":-8669,"年間":-1626,"府県":-2363,"手権":-1982,"新聞":-4066,"日新":-722,"日本":-7068,"日米":3372,"曜日":-601,"朝鮮":-2355,"本人":-2697,"東京":-1543,"然と":-1384,"社会":-1276,"立て":-990,"第に":-1612,"米国":-4268,"11":-669};
|
||||
this.BW3__ = {"あた":-2194,"あり":719,"ある":3846,"い.":-1185,"い。":-1185,"いい":5308,"いえ":2079,"いく":3029,"いた":2056,"いっ":1883,"いる":5600,"いわ":1527,"うち":1117,"うと":4798,"えと":1454,"か.":2857,"か。":2857,"かけ":-743,"かっ":-4098,"かに":-669,"から":6520,"かり":-2670,"が,":1816,"が、":1816,"がき":-4855,"がけ":-1127,"がっ":-913,"がら":-4977,"がり":-2064,"きた":1645,"けど":1374,"こと":7397,"この":1542,"ころ":-2757,"さい":-714,"さを":976,"し,":1557,"し、":1557,"しい":-3714,"した":3562,"して":1449,"しな":2608,"しま":1200,"す.":-1310,"す。":-1310,"する":6521,"ず,":3426,"ず、":3426,"ずに":841,"そう":428,"た.":8875,"た。":8875,"たい":-594,"たの":812,"たり":-1183,"たる":-853,"だ.":4098,"だ。":4098,"だっ":1004,"った":-4748,"って":300,"てい":6240,"てお":855,"ても":302,"です":1437,"でに":-1482,"では":2295,"とう":-1387,"とし":2266,"との":541,"とも":-3543,"どう":4664,"ない":1796,"なく":-903,"など":2135,"に,":-1021,"に、":-1021,"にし":1771,"にな":1906,"には":2644,"の,":-724,"の、":-724,"の子":-1000,"は,":1337,"は、":1337,"べき":2181,"まし":1113,"ます":6943,"まっ":-1549,"まで":6154,"まれ":-793,"らし":1479,"られ":6820,"るる":3818,"れ,":854,"れ、":854,"れた":1850,"れて":1375,"れば":-3246,"れる":1091,"われ":-605,"んだ":606,"んで":798,"カ月":990,"会議":860,"入り":1232,"大会":2217,"始め":1681,"市":965,"新聞":-5055,"日,":974,"日、":974,"社会":2024,"カ月":990};
|
||||
this.TC1__ = {"AAA":1093,"HHH":1029,"HHM":580,"HII":998,"HOH":-390,"HOM":-331,"IHI":1169,"IOH":-142,"IOI":-1015,"IOM":467,"MMH":187,"OOI":-1832};
|
||||
this.TC2__ = {"HHO":2088,"HII":-1023,"HMM":-1154,"IHI":-1965,"KKH":703,"OII":-2649};
|
||||
this.TC3__ = {"AAA":-294,"HHH":346,"HHI":-341,"HII":-1088,"HIK":731,"HOH":-1486,"IHH":128,"IHI":-3041,"IHO":-1935,"IIH":-825,"IIM":-1035,"IOI":-542,"KHH":-1216,"KKA":491,"KKH":-1217,"KOK":-1009,"MHH":-2694,"MHM":-457,"MHO":123,"MMH":-471,"NNH":-1689,"NNO":662,"OHO":-3393};
|
||||
this.TC4__ = {"HHH":-203,"HHI":1344,"HHK":365,"HHM":-122,"HHN":182,"HHO":669,"HIH":804,"HII":679,"HOH":446,"IHH":695,"IHO":-2324,"IIH":321,"III":1497,"IIO":656,"IOO":54,"KAK":4845,"KKA":3386,"KKK":3065,"MHH":-405,"MHI":201,"MMH":-241,"MMM":661,"MOM":841};
|
||||
this.TQ1__ = {"BHHH":-227,"BHHI":316,"BHIH":-132,"BIHH":60,"BIII":1595,"BNHH":-744,"BOHH":225,"BOOO":-908,"OAKK":482,"OHHH":281,"OHIH":249,"OIHI":200,"OIIH":-68};
|
||||
this.TQ2__ = {"BIHH":-1401,"BIII":-1033,"BKAK":-543,"BOOO":-5591};
|
||||
this.TQ3__ = {"BHHH":478,"BHHM":-1073,"BHIH":222,"BHII":-504,"BIIH":-116,"BIII":-105,"BMHI":-863,"BMHM":-464,"BOMH":620,"OHHH":346,"OHHI":1729,"OHII":997,"OHMH":481,"OIHH":623,"OIIH":1344,"OKAK":2792,"OKHH":587,"OKKA":679,"OOHH":110,"OOII":-685};
|
||||
this.TQ4__ = {"BHHH":-721,"BHHM":-3604,"BHII":-966,"BIIH":-607,"BIII":-2181,"OAAA":-2763,"OAKK":180,"OHHH":-294,"OHHI":2446,"OHHO":480,"OHIH":-1573,"OIHH":1935,"OIHI":-493,"OIIH":626,"OIII":-4007,"OKAK":-8156};
|
||||
this.TW1__ = {"につい":-4681,"東京都":2026};
|
||||
this.TW2__ = {"ある程":-2049,"いった":-1256,"ころが":-2434,"しょう":3873,"その後":-4430,"だって":-1049,"ていた":1833,"として":-4657,"ともに":-4517,"もので":1882,"一気に":-792,"初めて":-1512,"同時に":-8097,"大きな":-1255,"対して":-2721,"社会党":-3216};
|
||||
this.TW3__ = {"いただ":-1734,"してい":1314,"として":-4314,"につい":-5483,"にとっ":-5989,"に当た":-6247,"ので,":-727,"ので、":-727,"のもの":-600,"れから":-3752,"十二月":-2287};
|
||||
this.TW4__ = {"いう.":8576,"いう。":8576,"からな":-2348,"してい":2958,"たが,":1516,"たが、":1516,"ている":1538,"という":1349,"ました":5543,"ません":1097,"ようと":-4258,"よると":5865};
|
||||
this.UC1__ = {"A":484,"K":93,"M":645,"O":-505};
|
||||
this.UC2__ = {"A":819,"H":1059,"I":409,"M":3987,"N":5775,"O":646};
|
||||
this.UC3__ = {"A":-1370,"I":2311};
|
||||
this.UC4__ = {"A":-2643,"H":1809,"I":-1032,"K":-3450,"M":3565,"N":3876,"O":6646};
|
||||
this.UC5__ = {"H":313,"I":-1238,"K":-799,"M":539,"O":-831};
|
||||
this.UC6__ = {"H":-506,"I":-253,"K":87,"M":247,"O":-387};
|
||||
this.UP1__ = {"O":-214};
|
||||
this.UP2__ = {"B":69,"O":935};
|
||||
this.UP3__ = {"B":189};
|
||||
this.UQ1__ = {"BH":21,"BI":-12,"BK":-99,"BN":142,"BO":-56,"OH":-95,"OI":477,"OK":410,"OO":-2422};
|
||||
this.UQ2__ = {"BH":216,"BI":113,"OK":1759};
|
||||
this.UQ3__ = {"BA":-479,"BH":42,"BI":1913,"BK":-7198,"BM":3160,"BN":6427,"BO":14761,"OI":-827,"ON":-3212};
|
||||
this.UW1__ = {",":156,"、":156,"「":-463,"あ":-941,"う":-127,"が":-553,"き":121,"こ":505,"で":-201,"と":-547,"ど":-123,"に":-789,"の":-185,"は":-847,"も":-466,"や":-470,"よ":182,"ら":-292,"り":208,"れ":169,"を":-446,"ん":-137,"・":-135,"主":-402,"京":-268,"区":-912,"午":871,"国":-460,"大":561,"委":729,"市":-411,"日":-141,"理":361,"生":-408,"県":-386,"都":-718,"「":-463,"・":-135};
|
||||
this.UW2__ = {",":-829,"、":-829,"〇":892,"「":-645,"」":3145,"あ":-538,"い":505,"う":134,"お":-502,"か":1454,"が":-856,"く":-412,"こ":1141,"さ":878,"ざ":540,"し":1529,"す":-675,"せ":300,"そ":-1011,"た":188,"だ":1837,"つ":-949,"て":-291,"で":-268,"と":-981,"ど":1273,"な":1063,"に":-1764,"の":130,"は":-409,"ひ":-1273,"べ":1261,"ま":600,"も":-1263,"や":-402,"よ":1639,"り":-579,"る":-694,"れ":571,"を":-2516,"ん":2095,"ア":-587,"カ":306,"キ":568,"ッ":831,"三":-758,"不":-2150,"世":-302,"中":-968,"主":-861,"事":492,"人":-123,"会":978,"保":362,"入":548,"初":-3025,"副":-1566,"北":-3414,"区":-422,"大":-1769,"天":-865,"太":-483,"子":-1519,"学":760,"実":1023,"小":-2009,"市":-813,"年":-1060,"強":1067,"手":-1519,"揺":-1033,"政":1522,"文":-1355,"新":-1682,"日":-1815,"明":-1462,"最":-630,"朝":-1843,"本":-1650,"東":-931,"果":-665,"次":-2378,"民":-180,"気":-1740,"理":752,"発":529,"目":-1584,"相":-242,"県":-1165,"立":-763,"第":810,"米":509,"自":-1353,"行":838,"西":-744,"見":-3874,"調":1010,"議":1198,"込":3041,"開":1758,"間":-1257,"「":-645,"」":3145,"ッ":831,"ア":-587,"カ":306,"キ":568};
|
||||
this.UW3__ = {",":4889,"1":-800,"−":-1723,"、":4889,"々":-2311,"〇":5827,"」":2670,"〓":-3573,"あ":-2696,"い":1006,"う":2342,"え":1983,"お":-4864,"か":-1163,"が":3271,"く":1004,"け":388,"げ":401,"こ":-3552,"ご":-3116,"さ":-1058,"し":-395,"す":584,"せ":3685,"そ":-5228,"た":842,"ち":-521,"っ":-1444,"つ":-1081,"て":6167,"で":2318,"と":1691,"ど":-899,"な":-2788,"に":2745,"の":4056,"は":4555,"ひ":-2171,"ふ":-1798,"へ":1199,"ほ":-5516,"ま":-4384,"み":-120,"め":1205,"も":2323,"や":-788,"よ":-202,"ら":727,"り":649,"る":5905,"れ":2773,"わ":-1207,"を":6620,"ん":-518,"ア":551,"グ":1319,"ス":874,"ッ":-1350,"ト":521,"ム":1109,"ル":1591,"ロ":2201,"ン":278,"・":-3794,"一":-1619,"下":-1759,"世":-2087,"両":3815,"中":653,"主":-758,"予":-1193,"二":974,"人":2742,"今":792,"他":1889,"以":-1368,"低":811,"何":4265,"作":-361,"保":-2439,"元":4858,"党":3593,"全":1574,"公":-3030,"六":755,"共":-1880,"円":5807,"再":3095,"分":457,"初":2475,"別":1129,"前":2286,"副":4437,"力":365,"動":-949,"務":-1872,"化":1327,"北":-1038,"区":4646,"千":-2309,"午":-783,"協":-1006,"口":483,"右":1233,"各":3588,"合":-241,"同":3906,"和":-837,"員":4513,"国":642,"型":1389,"場":1219,"外":-241,"妻":2016,"学":-1356,"安":-423,"実":-1008,"家":1078,"小":-513,"少":-3102,"州":1155,"市":3197,"平":-1804,"年":2416,"広":-1030,"府":1605,"度":1452,"建":-2352,"当":-3885,"得":1905,"思":-1291,"性":1822,"戸":-488,"指":-3973,"政":-2013,"教":-1479,"数":3222,"文":-1489,"新":1764,"日":2099,"旧":5792,"昨":-661,"時":-1248,"曜":-951,"最":-937,"月":4125,"期":360,"李":3094,"村":364,"東":-805,"核":5156,"森":2438,"業":484,"氏":2613,"民":-1694,"決":-1073,"法":1868,"海":-495,"無":979,"物":461,"特":-3850,"生":-273,"用":914,"町":1215,"的":7313,"直":-1835,"省":792,"県":6293,"知":-1528,"私":4231,"税":401,"立":-960,"第":1201,"米":7767,"系":3066,"約":3663,"級":1384,"統":-4229,"総":1163,"線":1255,"者":6457,"能":725,"自":-2869,"英":785,"見":1044,"調":-562,"財":-733,"費":1777,"車":1835,"軍":1375,"込":-1504,"通":-1136,"選":-681,"郎":1026,"郡":4404,"部":1200,"金":2163,"長":421,"開":-1432,"間":1302,"関":-1282,"雨":2009,"電":-1045,"非":2066,"駅":1620,"1":-800,"」":2670,"・":-3794,"ッ":-1350,"ア":551,"グ":1319,"ス":874,"ト":521,"ム":1109,"ル":1591,"ロ":2201,"ン":278};
|
||||
this.UW4__ = {",":3930,".":3508,"―":-4841,"、":3930,"。":3508,"〇":4999,"「":1895,"」":3798,"〓":-5156,"あ":4752,"い":-3435,"う":-640,"え":-2514,"お":2405,"か":530,"が":6006,"き":-4482,"ぎ":-3821,"く":-3788,"け":-4376,"げ":-4734,"こ":2255,"ご":1979,"さ":2864,"し":-843,"じ":-2506,"す":-731,"ず":1251,"せ":181,"そ":4091,"た":5034,"だ":5408,"ち":-3654,"っ":-5882,"つ":-1659,"て":3994,"で":7410,"と":4547,"な":5433,"に":6499,"ぬ":1853,"ね":1413,"の":7396,"は":8578,"ば":1940,"ひ":4249,"び":-4134,"ふ":1345,"へ":6665,"べ":-744,"ほ":1464,"ま":1051,"み":-2082,"む":-882,"め":-5046,"も":4169,"ゃ":-2666,"や":2795,"ょ":-1544,"よ":3351,"ら":-2922,"り":-9726,"る":-14896,"れ":-2613,"ろ":-4570,"わ":-1783,"を":13150,"ん":-2352,"カ":2145,"コ":1789,"セ":1287,"ッ":-724,"ト":-403,"メ":-1635,"ラ":-881,"リ":-541,"ル":-856,"ン":-3637,"・":-4371,"ー":-11870,"一":-2069,"中":2210,"予":782,"事":-190,"井":-1768,"人":1036,"以":544,"会":950,"体":-1286,"作":530,"側":4292,"先":601,"党":-2006,"共":-1212,"内":584,"円":788,"初":1347,"前":1623,"副":3879,"力":-302,"動":-740,"務":-2715,"化":776,"区":4517,"協":1013,"参":1555,"合":-1834,"和":-681,"員":-910,"器":-851,"回":1500,"国":-619,"園":-1200,"地":866,"場":-1410,"塁":-2094,"士":-1413,"多":1067,"大":571,"子":-4802,"学":-1397,"定":-1057,"寺":-809,"小":1910,"屋":-1328,"山":-1500,"島":-2056,"川":-2667,"市":2771,"年":374,"庁":-4556,"後":456,"性":553,"感":916,"所":-1566,"支":856,"改":787,"政":2182,"教":704,"文":522,"方":-856,"日":1798,"時":1829,"最":845,"月":-9066,"木":-485,"来":-442,"校":-360,"業":-1043,"氏":5388,"民":-2716,"気":-910,"沢":-939,"済":-543,"物":-735,"率":672,"球":-1267,"生":-1286,"産":-1101,"田":-2900,"町":1826,"的":2586,"目":922,"省":-3485,"県":2997,"空":-867,"立":-2112,"第":788,"米":2937,"系":786,"約":2171,"経":1146,"統":-1169,"総":940,"線":-994,"署":749,"者":2145,"能":-730,"般":-852,"行":-792,"規":792,"警":-1184,"議":-244,"谷":-1000,"賞":730,"車":-1481,"軍":1158,"輪":-1433,"込":-3370,"近":929,"道":-1291,"選":2596,"郎":-4866,"都":1192,"野":-1100,"銀":-2213,"長":357,"間":-2344,"院":-2297,"際":-2604,"電":-878,"領":-1659,"題":-792,"館":-1984,"首":1749,"高":2120,"「":1895,"」":3798,"・":-4371,"ッ":-724,"ー":-11870,"カ":2145,"コ":1789,"セ":1287,"ト":-403,"メ":-1635,"ラ":-881,"リ":-541,"ル":-856,"ン":-3637};
|
||||
this.UW5__ = {",":465,".":-299,"1":-514,"E2":-32768,"]":-2762,"、":465,"。":-299,"「":363,"あ":1655,"い":331,"う":-503,"え":1199,"お":527,"か":647,"が":-421,"き":1624,"ぎ":1971,"く":312,"げ":-983,"さ":-1537,"し":-1371,"す":-852,"だ":-1186,"ち":1093,"っ":52,"つ":921,"て":-18,"で":-850,"と":-127,"ど":1682,"な":-787,"に":-1224,"の":-635,"は":-578,"べ":1001,"み":502,"め":865,"ゃ":3350,"ょ":854,"り":-208,"る":429,"れ":504,"わ":419,"を":-1264,"ん":327,"イ":241,"ル":451,"ン":-343,"中":-871,"京":722,"会":-1153,"党":-654,"務":3519,"区":-901,"告":848,"員":2104,"大":-1296,"学":-548,"定":1785,"嵐":-1304,"市":-2991,"席":921,"年":1763,"思":872,"所":-814,"挙":1618,"新":-1682,"日":218,"月":-4353,"査":932,"格":1356,"機":-1508,"氏":-1347,"田":240,"町":-3912,"的":-3149,"相":1319,"省":-1052,"県":-4003,"研":-997,"社":-278,"空":-813,"統":1955,"者":-2233,"表":663,"語":-1073,"議":1219,"選":-1018,"郎":-368,"長":786,"間":1191,"題":2368,"館":-689,"1":-514,"E2":-32768,"「":363,"イ":241,"ル":451,"ン":-343};
|
||||
this.UW6__ = {",":227,".":808,"1":-270,"E1":306,"、":227,"。":808,"あ":-307,"う":189,"か":241,"が":-73,"く":-121,"こ":-200,"じ":1782,"す":383,"た":-428,"っ":573,"て":-1014,"で":101,"と":-105,"な":-253,"に":-149,"の":-417,"は":-236,"も":-206,"り":187,"る":-135,"を":195,"ル":-673,"ン":-496,"一":-277,"中":201,"件":-800,"会":624,"前":302,"区":1792,"員":-1212,"委":798,"学":-960,"市":887,"広":-695,"後":535,"業":-697,"相":753,"社":-507,"福":974,"空":-822,"者":1811,"連":463,"郎":1082,"1":-270,"E1":306,"ル":-673,"ン":-496};
|
||||
|
||||
return this;
|
||||
}
|
||||
TinySegmenter.prototype.ctype_ = function(str) {
|
||||
for (var i in this.chartype_) {
|
||||
if (str.match(this.chartype_[i][0])) {
|
||||
return this.chartype_[i][1];
|
||||
}
|
||||
}
|
||||
return "O";
|
||||
}
|
||||
|
||||
TinySegmenter.prototype.ts_ = function(v) {
|
||||
if (v) { return v; }
|
||||
return 0;
|
||||
}
|
||||
|
||||
TinySegmenter.prototype.segment = function(input) {
|
||||
if (input == null || input == undefined || input == "") {
|
||||
return [];
|
||||
}
|
||||
var result = [];
|
||||
var seg = ["B3","B2","B1"];
|
||||
var ctype = ["O","O","O"];
|
||||
var o = input.split("");
|
||||
for (i = 0; i < o.length; ++i) {
|
||||
seg.push(o[i]);
|
||||
ctype.push(this.ctype_(o[i]))
|
||||
}
|
||||
seg.push("E1");
|
||||
seg.push("E2");
|
||||
seg.push("E3");
|
||||
ctype.push("O");
|
||||
ctype.push("O");
|
||||
ctype.push("O");
|
||||
var word = seg[3];
|
||||
var p1 = "U";
|
||||
var p2 = "U";
|
||||
var p3 = "U";
|
||||
for (var i = 4; i < seg.length - 3; ++i) {
|
||||
var score = this.BIAS__;
|
||||
var w1 = seg[i-3];
|
||||
var w2 = seg[i-2];
|
||||
var w3 = seg[i-1];
|
||||
var w4 = seg[i];
|
||||
var w5 = seg[i+1];
|
||||
var w6 = seg[i+2];
|
||||
var c1 = ctype[i-3];
|
||||
var c2 = ctype[i-2];
|
||||
var c3 = ctype[i-1];
|
||||
var c4 = ctype[i];
|
||||
var c5 = ctype[i+1];
|
||||
var c6 = ctype[i+2];
|
||||
score += this.ts_(this.UP1__[p1]);
|
||||
score += this.ts_(this.UP2__[p2]);
|
||||
score += this.ts_(this.UP3__[p3]);
|
||||
score += this.ts_(this.BP1__[p1 + p2]);
|
||||
score += this.ts_(this.BP2__[p2 + p3]);
|
||||
score += this.ts_(this.UW1__[w1]);
|
||||
score += this.ts_(this.UW2__[w2]);
|
||||
score += this.ts_(this.UW3__[w3]);
|
||||
score += this.ts_(this.UW4__[w4]);
|
||||
score += this.ts_(this.UW5__[w5]);
|
||||
score += this.ts_(this.UW6__[w6]);
|
||||
score += this.ts_(this.BW1__[w2 + w3]);
|
||||
score += this.ts_(this.BW2__[w3 + w4]);
|
||||
score += this.ts_(this.BW3__[w4 + w5]);
|
||||
score += this.ts_(this.TW1__[w1 + w2 + w3]);
|
||||
score += this.ts_(this.TW2__[w2 + w3 + w4]);
|
||||
score += this.ts_(this.TW3__[w3 + w4 + w5]);
|
||||
score += this.ts_(this.TW4__[w4 + w5 + w6]);
|
||||
score += this.ts_(this.UC1__[c1]);
|
||||
score += this.ts_(this.UC2__[c2]);
|
||||
score += this.ts_(this.UC3__[c3]);
|
||||
score += this.ts_(this.UC4__[c4]);
|
||||
score += this.ts_(this.UC5__[c5]);
|
||||
score += this.ts_(this.UC6__[c6]);
|
||||
score += this.ts_(this.BC1__[c2 + c3]);
|
||||
score += this.ts_(this.BC2__[c3 + c4]);
|
||||
score += this.ts_(this.BC3__[c4 + c5]);
|
||||
score += this.ts_(this.TC1__[c1 + c2 + c3]);
|
||||
score += this.ts_(this.TC2__[c2 + c3 + c4]);
|
||||
score += this.ts_(this.TC3__[c3 + c4 + c5]);
|
||||
score += this.ts_(this.TC4__[c4 + c5 + c6]);
|
||||
// score += this.ts_(this.TC5__[c4 + c5 + c6]);
|
||||
score += this.ts_(this.UQ1__[p1 + c1]);
|
||||
score += this.ts_(this.UQ2__[p2 + c2]);
|
||||
score += this.ts_(this.UQ3__[p3 + c3]);
|
||||
score += this.ts_(this.BQ1__[p2 + c2 + c3]);
|
||||
score += this.ts_(this.BQ2__[p2 + c3 + c4]);
|
||||
score += this.ts_(this.BQ3__[p3 + c2 + c3]);
|
||||
score += this.ts_(this.BQ4__[p3 + c3 + c4]);
|
||||
score += this.ts_(this.TQ1__[p2 + c1 + c2 + c3]);
|
||||
score += this.ts_(this.TQ2__[p2 + c2 + c3 + c4]);
|
||||
score += this.ts_(this.TQ3__[p3 + c1 + c2 + c3]);
|
||||
score += this.ts_(this.TQ4__[p3 + c2 + c3 + c4]);
|
||||
var p = "O";
|
||||
if (score > 0) {
|
||||
result.push(word);
|
||||
word = "";
|
||||
p = "B";
|
||||
}
|
||||
p1 = p2;
|
||||
p2 = p3;
|
||||
p3 = p;
|
||||
word += seg[i];
|
||||
}
|
||||
result.push(word);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
lunr.TinySegmenter = TinySegmenter;
|
||||
};
|
||||
|
||||
}));
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["src/templates/assets/stylesheets/palette/_scheme.scss","../../../../src/templates/assets/stylesheets/palette.scss","src/templates/assets/stylesheets/palette/_accent.scss","src/templates/assets/stylesheets/palette/_primary.scss","src/templates/assets/stylesheets/utilities/_break.scss"],"names":[],"mappings":"AA2BA,cAGE,6BAME,sDAAA,CACA,6DAAA,CACA,+DAAA,CACA,gEAAA,CACA,mDAAA,CACA,6DAAA,CACA,+DAAA,CACA,gEAAA,CAGA,mDAAA,CACA,gDAAA,CACA,yDAAA,CACA,4DAAA,CAGA,0BAAA,CACA,mCAAA,CAGA,iCAAA,CACA,kCAAA,CACA,mCAAA,CACA,mCAAA,CACA,kCAAA,CACA,iCAAA,CACA,+CAAA,CACA,6DAAA,CACA,gEAAA,CACA,4DAAA,CACA,4DAAA,CACA,6DAAA,CAGA,6CAAA,CAGA,+CAAA,CAGA,uDAAA,CACA,6DAAA,CACA,2DAAA,CAGA,iCAAA,CAGA,yDAAA,CACA,iEAAA,CAGA,mDAAA,CACA,mDAAA,CAGA,qDAAA,CACA,uDAAA,CAGA,8DAAA,CAKA,8DAAA,CAKA,0DAAA,CAzEA,iBCiBF,CD6DE,kHAEE,YC3DJ,CDkFE,yDACE,4BChFJ,CD+EE,2DACE,4BC7EJ,CD4EE,gEACE,4BC1EJ,CDyEE,2DACE,4BCvEJ,CDsEE,yDACE,4BCpEJ,CDmEE,0DACE,4BCjEJ,CDgEE,gEACE,4BC9DJ,CD6DE,0DACE,4BC3DJ,CD0DE,2OACE,4BC/CJ,CDsDA,+FAGE,iCCpDF,CACF,CCjDE,2BACE,4BAAA,CACA,2CAAA,CAOE,yBAAA,CACA,qCD6CN,CCvDE,4BACE,4BAAA,CACA,2CAAA,CAOE,yBAAA,CACA,qCDoDN,CC9DE,8BACE,4BAAA,CACA,2CAAA,CAOE,yBAAA,CACA,qCD2DN,CCrEE,mCACE,4BAAA,CACA,2CAAA,CAOE,yBAAA,CACA,qCDkEN,CC5EE,8BACE,4BAAA,CACA,2CAAA,CAOE,yBAAA,CACA,qCDyEN,CCnFE,4BACE,4BAAA,CACA,2CAAA,CAOE,yBAAA,CACA,qCDgFN,CC1FE,kCACE,4BAAA,CACA,2CAAA,CAOE,yBAAA,CACA,qCDuFN,CCjGE,4BACE,4BAAA,CACA,2CAAA,CAOE,yBAAA,CACA,qCD8FN,CCxGE,4BACE,4BAAA,CACA,2CAAA,CAOE,yBAAA,CACA,qCDqGN,CC/GE,6BACE,4BAAA,CACA,2CAAA,CAOE,yBAAA,CACA,qCD4GN,CCtHE,mCACE,4BAAA,CACA,2CAAA,CAOE,yBAAA,CACA,qCDmHN,CC7HE,4BACE,4BAAA,CACA,2CAAA,CAIE,8BAAA,CACA,qCD6HN,CCpIE,8BACE,4BAAA,CACA,2CAAA,CAIE,8BAAA,CACA,qCDoIN,CC3IE,6BACE,yBAAA,CACA,2CAAA,CAIE,8BAAA,CACA,qCD2IN,CClJE,8BACE,4BAAA,CACA,2CAAA,CAIE,8BAAA,CACA,qCDkJN,CCzJE,mCACE,4BAAA,CACA,2CAAA,CAOE,yBAAA,CACA,qCDsJN,CE3JE,4BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,sCFwJN,CEnKE,6BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,sCFgKN,CE3KE,+BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,sCFwKN,CEnLE,oCACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,sCFgLN,CE3LE,+BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,sCFwLN,CEnME,6BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,sCFgMN,CE3ME,mCACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,sCFwMN,CEnNE,6BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,sCFgNN,CE3NE,6BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,sCFwNN,CEnOE,8BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,sCFgON,CE3OE,oCACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,sCFwON,CEnPE,6BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAIE,+BAAA,CACA,sCFmPN,CE3PE,+BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAIE,+BAAA,CACA,sCF2PN,CEnQE,8BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAIE,+BAAA,CACA,sCFmQN,CE3QE,+BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAIE,+BAAA,CACA,sCF2QN,CEnRE,oCACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,sCFgRN,CE3RE,8BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,sCFwRN,CEnSE,6BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,sCAAA,CAKA,4BF4RN,CE5SE,kCACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,sCAAA,CAKA,4BFqSN,CEtRE,sEACE,4BFyRJ,CE1RE,+DACE,4BF6RJ,CE9RE,iEACE,4BFiSJ,CElSE,gEACE,4BFqSJ,CEtSE,iEACE,4BFySJ,CEhSA,8BACE,mDAAA,CACA,4DAAA,CACA,0DAAA,CACA,oDAAA,CACA,2DAAA,CAGA,4BFiSF,CE9RE,yCACE,+BFgSJ,CE7RI,kDAEE,0CAAA,CACA,sCAAA,CAFA,mCFiSN,CG7MI,mCD1EA,+CACE,8CF0RJ,CEvRI,qDACE,8CFyRN,CEpRE,iEACE,mCFsRJ,CACF,CGxNI,sCDvDA,uCACE,oCFkRJ,CACF,CEzQA,8BACE,kDAAA,CACA,4DAAA,CACA,wDAAA,CACA,oDAAA,CACA,6DAAA,CAGA,4BF0QF,CEvQE,yCACE,+BFyQJ,CEtQI,kDAEE,0CAAA,CACA,sCAAA,CAFA,mCF0QN,CEnQE,yCACE,6CFqQJ,CG9NI,0CDhCA,8CACE,gDFiQJ,CACF,CGnOI,0CDvBA,iFACE,6CF6PJ,CACF,CG3PI,sCDKA,uCACE,6CFyPJ,CACF","file":"palette.css"}
|
||||
@@ -1 +0,0 @@
|
||||
*
|
||||
@@ -1,8 +0,0 @@
|
||||
#!/bin/bash
|
||||
# note: if we compile tinygrad/nn/__init__.py __dict__ no longer works, and optimizers will silently fail
|
||||
mypyc --check-untyped-defs --explicit-package-bases --warn-unreachable tinygrad/shape/shapetracker.py tinygrad/shape/symbolic.py \
|
||||
tinygrad/helpers.py tinygrad/mlops.py tinygrad/tensor.py tinygrad/graph.py \
|
||||
#tinygrad/codegen/gpu.py tinygrad/runtime/ops_metal.py
|
||||
#tinygrad/codegen/ast.py
|
||||
#tinygrad/nn/__init__.py
|
||||
#tinygrad/ops.py tinygrad/runtime/ops_metal.py tinygrad/runtime/ops_gpu.py tinygrad/runtime/ops_cpu.py tinygrad/lazy.py
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1 +0,0 @@
|
||||
disasm.so
|
||||
@@ -1,5 +0,0 @@
|
||||
From the Freedreno project
|
||||
|
||||
https://gallium.readthedocs.io/en/latest/gallium/drivers/freedreno.html
|
||||
|
||||
In Mesa3D, so licensed MIT.
|
||||
@@ -1,18 +0,0 @@
|
||||
import ctypes
|
||||
import os
|
||||
import pathlib
|
||||
from hexdump import hexdump
|
||||
|
||||
fxn = None
|
||||
def disasm(buf):
|
||||
global fxn
|
||||
if fxn is None:
|
||||
shared = pathlib.Path(__file__).parent / "disasm.so"
|
||||
if not os.path.isfile(shared):
|
||||
os.system(f'cd {pathlib.Path(__file__).parent} && gcc -shared disasm-a3xx.c -o disasm.so')
|
||||
fxn = ctypes.CDLL(shared.as_posix())['disasm']
|
||||
#hexdump(buf)
|
||||
END = b"\x00\x00\x00\x00\x00\x00\x00\x03"
|
||||
buf = buf[0x510:] # this right?
|
||||
buf = buf.split(END)[0] + END
|
||||
fxn(buf, len(buf))
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,906 +0,0 @@
|
||||
/*
|
||||
* Mesa 3-D graphics library
|
||||
*
|
||||
* Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
|
||||
* Copyright (C) 2009 VMware, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef SHADER_ENUMS_H
|
||||
#define SHADER_ENUMS_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
/* Project-wide (GL and Vulkan) maximum. */
|
||||
#define MAX_DRAW_BUFFERS 8
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Shader stages.
|
||||
*
|
||||
* The order must match how shaders are ordered in the pipeline.
|
||||
* The GLSL linker assumes that if i<j, then the j-th shader is
|
||||
* executed later than the i-th shader.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
MESA_SHADER_NONE = -1,
|
||||
MESA_SHADER_VERTEX = 0,
|
||||
MESA_SHADER_TESS_CTRL = 1,
|
||||
MESA_SHADER_TESS_EVAL = 2,
|
||||
MESA_SHADER_GEOMETRY = 3,
|
||||
MESA_SHADER_FRAGMENT = 4,
|
||||
MESA_SHADER_COMPUTE = 5,
|
||||
/* must be last so it doesn't affect the GL pipeline */
|
||||
MESA_SHADER_KERNEL = 6,
|
||||
} gl_shader_stage;
|
||||
|
||||
static inline bool
|
||||
gl_shader_stage_is_compute(gl_shader_stage stage)
|
||||
{
|
||||
return stage == MESA_SHADER_COMPUTE || stage == MESA_SHADER_KERNEL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Number of STATE_* values we need to address any GL state.
|
||||
* Used to dimension arrays.
|
||||
*/
|
||||
#define STATE_LENGTH 5
|
||||
|
||||
typedef short gl_state_index16; /* see enum gl_state_index */
|
||||
|
||||
const char *gl_shader_stage_name(gl_shader_stage stage);
|
||||
|
||||
/**
|
||||
* Translate a gl_shader_stage to a short shader stage name for debug
|
||||
* printouts and error messages.
|
||||
*/
|
||||
const char *_mesa_shader_stage_to_string(unsigned stage);
|
||||
|
||||
/**
|
||||
* Translate a gl_shader_stage to a shader stage abbreviation (VS, GS, FS)
|
||||
* for debug printouts and error messages.
|
||||
*/
|
||||
const char *_mesa_shader_stage_to_abbrev(unsigned stage);
|
||||
|
||||
/**
|
||||
* GL related stages (not including CL)
|
||||
*/
|
||||
#define MESA_SHADER_STAGES (MESA_SHADER_COMPUTE + 1)
|
||||
|
||||
/**
|
||||
* All stages
|
||||
*/
|
||||
#define MESA_ALL_SHADER_STAGES (MESA_SHADER_KERNEL + 1)
|
||||
|
||||
|
||||
/**
|
||||
* Indexes for vertex program attributes.
|
||||
* GL_NV_vertex_program aliases generic attributes over the conventional
|
||||
* attributes. In GL_ARB_vertex_program shader the aliasing is optional.
|
||||
* In GL_ARB_vertex_shader / OpenGL 2.0 the aliasing is disallowed (the
|
||||
* generic attributes are distinct/separate).
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
VERT_ATTRIB_POS,
|
||||
VERT_ATTRIB_NORMAL,
|
||||
VERT_ATTRIB_COLOR0,
|
||||
VERT_ATTRIB_COLOR1,
|
||||
VERT_ATTRIB_FOG,
|
||||
VERT_ATTRIB_COLOR_INDEX,
|
||||
VERT_ATTRIB_EDGEFLAG,
|
||||
VERT_ATTRIB_TEX0,
|
||||
VERT_ATTRIB_TEX1,
|
||||
VERT_ATTRIB_TEX2,
|
||||
VERT_ATTRIB_TEX3,
|
||||
VERT_ATTRIB_TEX4,
|
||||
VERT_ATTRIB_TEX5,
|
||||
VERT_ATTRIB_TEX6,
|
||||
VERT_ATTRIB_TEX7,
|
||||
VERT_ATTRIB_POINT_SIZE,
|
||||
VERT_ATTRIB_GENERIC0,
|
||||
VERT_ATTRIB_GENERIC1,
|
||||
VERT_ATTRIB_GENERIC2,
|
||||
VERT_ATTRIB_GENERIC3,
|
||||
VERT_ATTRIB_GENERIC4,
|
||||
VERT_ATTRIB_GENERIC5,
|
||||
VERT_ATTRIB_GENERIC6,
|
||||
VERT_ATTRIB_GENERIC7,
|
||||
VERT_ATTRIB_GENERIC8,
|
||||
VERT_ATTRIB_GENERIC9,
|
||||
VERT_ATTRIB_GENERIC10,
|
||||
VERT_ATTRIB_GENERIC11,
|
||||
VERT_ATTRIB_GENERIC12,
|
||||
VERT_ATTRIB_GENERIC13,
|
||||
VERT_ATTRIB_GENERIC14,
|
||||
VERT_ATTRIB_GENERIC15,
|
||||
VERT_ATTRIB_MAX
|
||||
} gl_vert_attrib;
|
||||
|
||||
const char *gl_vert_attrib_name(gl_vert_attrib attrib);
|
||||
|
||||
/**
|
||||
* Symbolic constats to help iterating over
|
||||
* specific blocks of vertex attributes.
|
||||
*
|
||||
* VERT_ATTRIB_FF
|
||||
* includes all fixed function attributes as well as
|
||||
* the aliased GL_NV_vertex_program shader attributes.
|
||||
* VERT_ATTRIB_TEX
|
||||
* include the classic texture coordinate attributes.
|
||||
* Is a subset of VERT_ATTRIB_FF.
|
||||
* VERT_ATTRIB_GENERIC
|
||||
* include the OpenGL 2.0+ GLSL generic shader attributes.
|
||||
* These alias the generic GL_ARB_vertex_shader attributes.
|
||||
* VERT_ATTRIB_MAT
|
||||
* include the generic shader attributes used to alias
|
||||
* varying material values for the TNL shader programs.
|
||||
* They are located at the end of the generic attribute
|
||||
* block not to overlap with the generic 0 attribute.
|
||||
*/
|
||||
#define VERT_ATTRIB_FF(i) (VERT_ATTRIB_POS + (i))
|
||||
#define VERT_ATTRIB_FF_MAX VERT_ATTRIB_GENERIC0
|
||||
|
||||
#define VERT_ATTRIB_TEX(i) (VERT_ATTRIB_TEX0 + (i))
|
||||
#define VERT_ATTRIB_TEX_MAX MAX_TEXTURE_COORD_UNITS
|
||||
|
||||
#define VERT_ATTRIB_GENERIC(i) (VERT_ATTRIB_GENERIC0 + (i))
|
||||
#define VERT_ATTRIB_GENERIC_MAX MAX_VERTEX_GENERIC_ATTRIBS
|
||||
|
||||
#define VERT_ATTRIB_MAT0 \
|
||||
(VERT_ATTRIB_GENERIC_MAX - VERT_ATTRIB_MAT_MAX)
|
||||
#define VERT_ATTRIB_MAT(i) \
|
||||
VERT_ATTRIB_GENERIC((i) + VERT_ATTRIB_MAT0)
|
||||
#define VERT_ATTRIB_MAT_MAX MAT_ATTRIB_MAX
|
||||
|
||||
/**
|
||||
* Bitflags for vertex attributes.
|
||||
* These are used in bitfields in many places.
|
||||
*/
|
||||
/*@{*/
|
||||
#define VERT_BIT_POS BITFIELD_BIT(VERT_ATTRIB_POS)
|
||||
#define VERT_BIT_NORMAL BITFIELD_BIT(VERT_ATTRIB_NORMAL)
|
||||
#define VERT_BIT_COLOR0 BITFIELD_BIT(VERT_ATTRIB_COLOR0)
|
||||
#define VERT_BIT_COLOR1 BITFIELD_BIT(VERT_ATTRIB_COLOR1)
|
||||
#define VERT_BIT_FOG BITFIELD_BIT(VERT_ATTRIB_FOG)
|
||||
#define VERT_BIT_COLOR_INDEX BITFIELD_BIT(VERT_ATTRIB_COLOR_INDEX)
|
||||
#define VERT_BIT_EDGEFLAG BITFIELD_BIT(VERT_ATTRIB_EDGEFLAG)
|
||||
#define VERT_BIT_TEX0 BITFIELD_BIT(VERT_ATTRIB_TEX0)
|
||||
#define VERT_BIT_TEX1 BITFIELD_BIT(VERT_ATTRIB_TEX1)
|
||||
#define VERT_BIT_TEX2 BITFIELD_BIT(VERT_ATTRIB_TEX2)
|
||||
#define VERT_BIT_TEX3 BITFIELD_BIT(VERT_ATTRIB_TEX3)
|
||||
#define VERT_BIT_TEX4 BITFIELD_BIT(VERT_ATTRIB_TEX4)
|
||||
#define VERT_BIT_TEX5 BITFIELD_BIT(VERT_ATTRIB_TEX5)
|
||||
#define VERT_BIT_TEX6 BITFIELD_BIT(VERT_ATTRIB_TEX6)
|
||||
#define VERT_BIT_TEX7 BITFIELD_BIT(VERT_ATTRIB_TEX7)
|
||||
#define VERT_BIT_POINT_SIZE BITFIELD_BIT(VERT_ATTRIB_POINT_SIZE)
|
||||
#define VERT_BIT_GENERIC0 BITFIELD_BIT(VERT_ATTRIB_GENERIC0)
|
||||
|
||||
#define VERT_BIT(i) BITFIELD_BIT(i)
|
||||
#define VERT_BIT_ALL BITFIELD_RANGE(0, VERT_ATTRIB_MAX)
|
||||
|
||||
#define VERT_BIT_FF(i) VERT_BIT(i)
|
||||
#define VERT_BIT_FF_ALL BITFIELD_RANGE(0, VERT_ATTRIB_FF_MAX)
|
||||
#define VERT_BIT_TEX(i) VERT_BIT(VERT_ATTRIB_TEX(i))
|
||||
#define VERT_BIT_TEX_ALL \
|
||||
BITFIELD_RANGE(VERT_ATTRIB_TEX(0), VERT_ATTRIB_TEX_MAX)
|
||||
|
||||
#define VERT_BIT_GENERIC(i) VERT_BIT(VERT_ATTRIB_GENERIC(i))
|
||||
#define VERT_BIT_GENERIC_ALL \
|
||||
BITFIELD_RANGE(VERT_ATTRIB_GENERIC(0), VERT_ATTRIB_GENERIC_MAX)
|
||||
|
||||
#define VERT_BIT_MAT(i) VERT_BIT(VERT_ATTRIB_MAT(i))
|
||||
#define VERT_BIT_MAT_ALL \
|
||||
BITFIELD_RANGE(VERT_ATTRIB_MAT(0), VERT_ATTRIB_MAT_MAX)
|
||||
/*@}*/
|
||||
|
||||
#define MAX_VARYING 32 /**< number of float[4] vectors */
|
||||
|
||||
/**
|
||||
* Indexes for vertex shader outputs, geometry shader inputs/outputs, and
|
||||
* fragment shader inputs.
|
||||
*
|
||||
* Note that some of these values are not available to all pipeline stages.
|
||||
*
|
||||
* When this enum is updated, the following code must be updated too:
|
||||
* - vertResults (in prog_print.c's arb_output_attrib_string())
|
||||
* - fragAttribs (in prog_print.c's arb_input_attrib_string())
|
||||
* - _mesa_varying_slot_in_fs()
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
VARYING_SLOT_POS,
|
||||
VARYING_SLOT_COL0, /* COL0 and COL1 must be contiguous */
|
||||
VARYING_SLOT_COL1,
|
||||
VARYING_SLOT_FOGC,
|
||||
VARYING_SLOT_TEX0, /* TEX0-TEX7 must be contiguous */
|
||||
VARYING_SLOT_TEX1,
|
||||
VARYING_SLOT_TEX2,
|
||||
VARYING_SLOT_TEX3,
|
||||
VARYING_SLOT_TEX4,
|
||||
VARYING_SLOT_TEX5,
|
||||
VARYING_SLOT_TEX6,
|
||||
VARYING_SLOT_TEX7,
|
||||
VARYING_SLOT_PSIZ, /* Does not appear in FS */
|
||||
VARYING_SLOT_BFC0, /* Does not appear in FS */
|
||||
VARYING_SLOT_BFC1, /* Does not appear in FS */
|
||||
VARYING_SLOT_EDGE, /* Does not appear in FS */
|
||||
VARYING_SLOT_CLIP_VERTEX, /* Does not appear in FS */
|
||||
VARYING_SLOT_CLIP_DIST0,
|
||||
VARYING_SLOT_CLIP_DIST1,
|
||||
VARYING_SLOT_CULL_DIST0,
|
||||
VARYING_SLOT_CULL_DIST1,
|
||||
VARYING_SLOT_PRIMITIVE_ID, /* Does not appear in VS */
|
||||
VARYING_SLOT_LAYER, /* Appears as VS or GS output */
|
||||
VARYING_SLOT_VIEWPORT, /* Appears as VS or GS output */
|
||||
VARYING_SLOT_FACE, /* FS only */
|
||||
VARYING_SLOT_PNTC, /* FS only */
|
||||
VARYING_SLOT_TESS_LEVEL_OUTER, /* Only appears as TCS output. */
|
||||
VARYING_SLOT_TESS_LEVEL_INNER, /* Only appears as TCS output. */
|
||||
VARYING_SLOT_BOUNDING_BOX0, /* Only appears as TCS output. */
|
||||
VARYING_SLOT_BOUNDING_BOX1, /* Only appears as TCS output. */
|
||||
VARYING_SLOT_VIEW_INDEX,
|
||||
VARYING_SLOT_VIEWPORT_MASK, /* Does not appear in FS */
|
||||
VARYING_SLOT_VAR0, /* First generic varying slot */
|
||||
/* the remaining are simply for the benefit of gl_varying_slot_name()
|
||||
* and not to be construed as an upper bound:
|
||||
*/
|
||||
VARYING_SLOT_VAR1,
|
||||
VARYING_SLOT_VAR2,
|
||||
VARYING_SLOT_VAR3,
|
||||
VARYING_SLOT_VAR4,
|
||||
VARYING_SLOT_VAR5,
|
||||
VARYING_SLOT_VAR6,
|
||||
VARYING_SLOT_VAR7,
|
||||
VARYING_SLOT_VAR8,
|
||||
VARYING_SLOT_VAR9,
|
||||
VARYING_SLOT_VAR10,
|
||||
VARYING_SLOT_VAR11,
|
||||
VARYING_SLOT_VAR12,
|
||||
VARYING_SLOT_VAR13,
|
||||
VARYING_SLOT_VAR14,
|
||||
VARYING_SLOT_VAR15,
|
||||
VARYING_SLOT_VAR16,
|
||||
VARYING_SLOT_VAR17,
|
||||
VARYING_SLOT_VAR18,
|
||||
VARYING_SLOT_VAR19,
|
||||
VARYING_SLOT_VAR20,
|
||||
VARYING_SLOT_VAR21,
|
||||
VARYING_SLOT_VAR22,
|
||||
VARYING_SLOT_VAR23,
|
||||
VARYING_SLOT_VAR24,
|
||||
VARYING_SLOT_VAR25,
|
||||
VARYING_SLOT_VAR26,
|
||||
VARYING_SLOT_VAR27,
|
||||
VARYING_SLOT_VAR28,
|
||||
VARYING_SLOT_VAR29,
|
||||
VARYING_SLOT_VAR30,
|
||||
VARYING_SLOT_VAR31,
|
||||
} gl_varying_slot;
|
||||
|
||||
|
||||
#define VARYING_SLOT_MAX (VARYING_SLOT_VAR0 + MAX_VARYING)
|
||||
#define VARYING_SLOT_PATCH0 (VARYING_SLOT_MAX)
|
||||
#define VARYING_SLOT_TESS_MAX (VARYING_SLOT_PATCH0 + MAX_VARYING)
|
||||
#define MAX_VARYINGS_INCL_PATCH (VARYING_SLOT_TESS_MAX - VARYING_SLOT_VAR0)
|
||||
|
||||
const char *gl_varying_slot_name(gl_varying_slot slot);
|
||||
|
||||
/**
|
||||
* Bitflags for varying slots.
|
||||
*/
|
||||
/*@{*/
|
||||
#define VARYING_BIT_POS BITFIELD64_BIT(VARYING_SLOT_POS)
|
||||
#define VARYING_BIT_COL0 BITFIELD64_BIT(VARYING_SLOT_COL0)
|
||||
#define VARYING_BIT_COL1 BITFIELD64_BIT(VARYING_SLOT_COL1)
|
||||
#define VARYING_BIT_FOGC BITFIELD64_BIT(VARYING_SLOT_FOGC)
|
||||
#define VARYING_BIT_TEX0 BITFIELD64_BIT(VARYING_SLOT_TEX0)
|
||||
#define VARYING_BIT_TEX1 BITFIELD64_BIT(VARYING_SLOT_TEX1)
|
||||
#define VARYING_BIT_TEX2 BITFIELD64_BIT(VARYING_SLOT_TEX2)
|
||||
#define VARYING_BIT_TEX3 BITFIELD64_BIT(VARYING_SLOT_TEX3)
|
||||
#define VARYING_BIT_TEX4 BITFIELD64_BIT(VARYING_SLOT_TEX4)
|
||||
#define VARYING_BIT_TEX5 BITFIELD64_BIT(VARYING_SLOT_TEX5)
|
||||
#define VARYING_BIT_TEX6 BITFIELD64_BIT(VARYING_SLOT_TEX6)
|
||||
#define VARYING_BIT_TEX7 BITFIELD64_BIT(VARYING_SLOT_TEX7)
|
||||
#define VARYING_BIT_TEX(U) BITFIELD64_BIT(VARYING_SLOT_TEX0 + (U))
|
||||
#define VARYING_BITS_TEX_ANY BITFIELD64_RANGE(VARYING_SLOT_TEX0, \
|
||||
MAX_TEXTURE_COORD_UNITS)
|
||||
#define VARYING_BIT_PSIZ BITFIELD64_BIT(VARYING_SLOT_PSIZ)
|
||||
#define VARYING_BIT_BFC0 BITFIELD64_BIT(VARYING_SLOT_BFC0)
|
||||
#define VARYING_BIT_BFC1 BITFIELD64_BIT(VARYING_SLOT_BFC1)
|
||||
#define VARYING_BITS_COLOR (VARYING_BIT_COL0 | \
|
||||
VARYING_BIT_COL1 | \
|
||||
VARYING_BIT_BFC0 | \
|
||||
VARYING_BIT_BFC1)
|
||||
#define VARYING_BIT_EDGE BITFIELD64_BIT(VARYING_SLOT_EDGE)
|
||||
#define VARYING_BIT_CLIP_VERTEX BITFIELD64_BIT(VARYING_SLOT_CLIP_VERTEX)
|
||||
#define VARYING_BIT_CLIP_DIST0 BITFIELD64_BIT(VARYING_SLOT_CLIP_DIST0)
|
||||
#define VARYING_BIT_CLIP_DIST1 BITFIELD64_BIT(VARYING_SLOT_CLIP_DIST1)
|
||||
#define VARYING_BIT_CULL_DIST0 BITFIELD64_BIT(VARYING_SLOT_CULL_DIST0)
|
||||
#define VARYING_BIT_CULL_DIST1 BITFIELD64_BIT(VARYING_SLOT_CULL_DIST1)
|
||||
#define VARYING_BIT_PRIMITIVE_ID BITFIELD64_BIT(VARYING_SLOT_PRIMITIVE_ID)
|
||||
#define VARYING_BIT_LAYER BITFIELD64_BIT(VARYING_SLOT_LAYER)
|
||||
#define VARYING_BIT_VIEWPORT BITFIELD64_BIT(VARYING_SLOT_VIEWPORT)
|
||||
#define VARYING_BIT_FACE BITFIELD64_BIT(VARYING_SLOT_FACE)
|
||||
#define VARYING_BIT_PNTC BITFIELD64_BIT(VARYING_SLOT_PNTC)
|
||||
#define VARYING_BIT_TESS_LEVEL_OUTER BITFIELD64_BIT(VARYING_SLOT_TESS_LEVEL_OUTER)
|
||||
#define VARYING_BIT_TESS_LEVEL_INNER BITFIELD64_BIT(VARYING_SLOT_TESS_LEVEL_INNER)
|
||||
#define VARYING_BIT_BOUNDING_BOX0 BITFIELD64_BIT(VARYING_SLOT_BOUNDING_BOX0)
|
||||
#define VARYING_BIT_BOUNDING_BOX1 BITFIELD64_BIT(VARYING_SLOT_BOUNDING_BOX1)
|
||||
#define VARYING_BIT_VIEWPORT_MASK BITFIELD64_BIT(VARYING_SLOT_VIEWPORT_MASK)
|
||||
#define VARYING_BIT_VAR(V) BITFIELD64_BIT(VARYING_SLOT_VAR0 + (V))
|
||||
/*@}*/
|
||||
|
||||
/**
|
||||
* Bitflags for system values.
|
||||
*/
|
||||
#define SYSTEM_BIT_SAMPLE_ID ((uint64_t)1 << SYSTEM_VALUE_SAMPLE_ID)
|
||||
#define SYSTEM_BIT_SAMPLE_POS ((uint64_t)1 << SYSTEM_VALUE_SAMPLE_POS)
|
||||
#define SYSTEM_BIT_SAMPLE_MASK_IN ((uint64_t)1 << SYSTEM_VALUE_SAMPLE_MASK_IN)
|
||||
#define SYSTEM_BIT_LOCAL_INVOCATION_ID ((uint64_t)1 << SYSTEM_VALUE_LOCAL_INVOCATION_ID)
|
||||
|
||||
/**
|
||||
* If the gl_register_file is PROGRAM_SYSTEM_VALUE, the register index will be
|
||||
* one of these values. If a NIR variable's mode is nir_var_system_value, it
|
||||
* will be one of these values.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
/**
|
||||
* \name System values applicable to all shaders
|
||||
*/
|
||||
/*@{*/
|
||||
|
||||
/**
|
||||
* Builtin variables added by GL_ARB_shader_ballot.
|
||||
*/
|
||||
/*@{*/
|
||||
|
||||
/**
|
||||
* From the GL_ARB_shader-ballot spec:
|
||||
*
|
||||
* "A sub-group is a collection of invocations which execute in lockstep.
|
||||
* The variable <gl_SubGroupSizeARB> is the maximum number of
|
||||
* invocations in a sub-group. The maximum <gl_SubGroupSizeARB>
|
||||
* supported in this extension is 64."
|
||||
*
|
||||
* The spec defines this as a uniform. However, it's highly unlikely that
|
||||
* implementations actually treat it as a uniform (which is loaded from a
|
||||
* constant buffer). Most likely, this is an implementation-wide constant,
|
||||
* or perhaps something that depends on the shader stage.
|
||||
*/
|
||||
SYSTEM_VALUE_SUBGROUP_SIZE,
|
||||
|
||||
/**
|
||||
* From the GL_ARB_shader_ballot spec:
|
||||
*
|
||||
* "The variable <gl_SubGroupInvocationARB> holds the index of the
|
||||
* invocation within sub-group. This variable is in the range 0 to
|
||||
* <gl_SubGroupSizeARB>-1, where <gl_SubGroupSizeARB> is the total
|
||||
* number of invocations in a sub-group."
|
||||
*/
|
||||
SYSTEM_VALUE_SUBGROUP_INVOCATION,
|
||||
|
||||
/**
|
||||
* From the GL_ARB_shader_ballot spec:
|
||||
*
|
||||
* "The <gl_SubGroup??MaskARB> variables provide a bitmask for all
|
||||
* invocations, with one bit per invocation starting with the least
|
||||
* significant bit, according to the following table,
|
||||
*
|
||||
* variable equation for bit values
|
||||
* -------------------- ------------------------------------
|
||||
* gl_SubGroupEqMaskARB bit index == gl_SubGroupInvocationARB
|
||||
* gl_SubGroupGeMaskARB bit index >= gl_SubGroupInvocationARB
|
||||
* gl_SubGroupGtMaskARB bit index > gl_SubGroupInvocationARB
|
||||
* gl_SubGroupLeMaskARB bit index <= gl_SubGroupInvocationARB
|
||||
* gl_SubGroupLtMaskARB bit index < gl_SubGroupInvocationARB
|
||||
*/
|
||||
SYSTEM_VALUE_SUBGROUP_EQ_MASK,
|
||||
SYSTEM_VALUE_SUBGROUP_GE_MASK,
|
||||
SYSTEM_VALUE_SUBGROUP_GT_MASK,
|
||||
SYSTEM_VALUE_SUBGROUP_LE_MASK,
|
||||
SYSTEM_VALUE_SUBGROUP_LT_MASK,
|
||||
/*@}*/
|
||||
|
||||
/**
|
||||
* Builtin variables added by VK_KHR_subgroups
|
||||
*/
|
||||
/*@{*/
|
||||
SYSTEM_VALUE_NUM_SUBGROUPS,
|
||||
SYSTEM_VALUE_SUBGROUP_ID,
|
||||
/*@}*/
|
||||
|
||||
/*@}*/
|
||||
|
||||
/**
|
||||
* \name Vertex shader system values
|
||||
*/
|
||||
/*@{*/
|
||||
/**
|
||||
* OpenGL-style vertex ID.
|
||||
*
|
||||
* Section 2.11.7 (Shader Execution), subsection Shader Inputs, of the
|
||||
* OpenGL 3.3 core profile spec says:
|
||||
*
|
||||
* "gl_VertexID holds the integer index i implicitly passed by
|
||||
* DrawArrays or one of the other drawing commands defined in section
|
||||
* 2.8.3."
|
||||
*
|
||||
* Section 2.8.3 (Drawing Commands) of the same spec says:
|
||||
*
|
||||
* "The commands....are equivalent to the commands with the same base
|
||||
* name (without the BaseVertex suffix), except that the ith element
|
||||
* transferred by the corresponding draw call will be taken from
|
||||
* element indices[i] + basevertex of each enabled array."
|
||||
*
|
||||
* Additionally, the overview in the GL_ARB_shader_draw_parameters spec
|
||||
* says:
|
||||
*
|
||||
* "In unextended GL, vertex shaders have inputs named gl_VertexID and
|
||||
* gl_InstanceID, which contain, respectively the index of the vertex
|
||||
* and instance. The value of gl_VertexID is the implicitly passed
|
||||
* index of the vertex being processed, which includes the value of
|
||||
* baseVertex, for those commands that accept it."
|
||||
*
|
||||
* gl_VertexID gets basevertex added in. This differs from DirectX where
|
||||
* SV_VertexID does \b not get basevertex added in.
|
||||
*
|
||||
* \note
|
||||
* If all system values are available, \c SYSTEM_VALUE_VERTEX_ID will be
|
||||
* equal to \c SYSTEM_VALUE_VERTEX_ID_ZERO_BASE plus
|
||||
* \c SYSTEM_VALUE_BASE_VERTEX.
|
||||
*
|
||||
* \sa SYSTEM_VALUE_VERTEX_ID_ZERO_BASE, SYSTEM_VALUE_BASE_VERTEX
|
||||
*/
|
||||
SYSTEM_VALUE_VERTEX_ID,
|
||||
|
||||
/**
|
||||
* Instanced ID as supplied to gl_InstanceID
|
||||
*
|
||||
* Values assigned to gl_InstanceID always begin with zero, regardless of
|
||||
* the value of baseinstance.
|
||||
*
|
||||
* Section 11.1.3.9 (Shader Inputs) of the OpenGL 4.4 core profile spec
|
||||
* says:
|
||||
*
|
||||
* "gl_InstanceID holds the integer instance number of the current
|
||||
* primitive in an instanced draw call (see section 10.5)."
|
||||
*
|
||||
* Through a big chain of pseudocode, section 10.5 describes that
|
||||
* baseinstance is not counted by gl_InstanceID. In that section, notice
|
||||
*
|
||||
* "If an enabled vertex attribute array is instanced (it has a
|
||||
* non-zero divisor as specified by VertexAttribDivisor), the element
|
||||
* index that is transferred to the GL, for all vertices, is given by
|
||||
*
|
||||
* floor(instance/divisor) + baseinstance
|
||||
*
|
||||
* If an array corresponding to an attribute required by a vertex
|
||||
* shader is not enabled, then the corresponding element is taken from
|
||||
* the current attribute state (see section 10.2)."
|
||||
*
|
||||
* Note that baseinstance is \b not included in the value of instance.
|
||||
*/
|
||||
SYSTEM_VALUE_INSTANCE_ID,
|
||||
|
||||
/**
|
||||
* Vulkan InstanceIndex.
|
||||
*
|
||||
* InstanceIndex = gl_InstanceID + gl_BaseInstance
|
||||
*/
|
||||
SYSTEM_VALUE_INSTANCE_INDEX,
|
||||
|
||||
/**
|
||||
* DirectX-style vertex ID.
|
||||
*
|
||||
* Unlike \c SYSTEM_VALUE_VERTEX_ID, this system value does \b not include
|
||||
* the value of basevertex.
|
||||
*
|
||||
* \sa SYSTEM_VALUE_VERTEX_ID, SYSTEM_VALUE_BASE_VERTEX
|
||||
*/
|
||||
SYSTEM_VALUE_VERTEX_ID_ZERO_BASE,
|
||||
|
||||
/**
|
||||
* Value of \c basevertex passed to \c glDrawElementsBaseVertex and similar
|
||||
* functions.
|
||||
*
|
||||
* \sa SYSTEM_VALUE_VERTEX_ID, SYSTEM_VALUE_VERTEX_ID_ZERO_BASE
|
||||
*/
|
||||
SYSTEM_VALUE_BASE_VERTEX,
|
||||
|
||||
/**
|
||||
* Depending on the type of the draw call (indexed or non-indexed),
|
||||
* is the value of \c basevertex passed to \c glDrawElementsBaseVertex and
|
||||
* similar, or is the value of \c first passed to \c glDrawArrays and
|
||||
* similar.
|
||||
*
|
||||
* \note
|
||||
* It can be used to calculate the \c SYSTEM_VALUE_VERTEX_ID as
|
||||
* \c SYSTEM_VALUE_VERTEX_ID_ZERO_BASE plus \c SYSTEM_VALUE_FIRST_VERTEX.
|
||||
*
|
||||
* \sa SYSTEM_VALUE_VERTEX_ID_ZERO_BASE, SYSTEM_VALUE_VERTEX_ID
|
||||
*/
|
||||
SYSTEM_VALUE_FIRST_VERTEX,
|
||||
|
||||
/**
|
||||
* If the Draw command used to start the rendering was an indexed draw
|
||||
* or not (~0/0). Useful to calculate \c SYSTEM_VALUE_BASE_VERTEX as
|
||||
* \c SYSTEM_VALUE_IS_INDEXED_DRAW & \c SYSTEM_VALUE_FIRST_VERTEX.
|
||||
*/
|
||||
SYSTEM_VALUE_IS_INDEXED_DRAW,
|
||||
|
||||
/**
|
||||
* Value of \c baseinstance passed to instanced draw entry points
|
||||
*
|
||||
* \sa SYSTEM_VALUE_INSTANCE_ID
|
||||
*/
|
||||
SYSTEM_VALUE_BASE_INSTANCE,
|
||||
|
||||
/**
|
||||
* From _ARB_shader_draw_parameters:
|
||||
*
|
||||
* "Additionally, this extension adds a further built-in variable,
|
||||
* gl_DrawID to the shading language. This variable contains the index
|
||||
* of the draw currently being processed by a Multi* variant of a
|
||||
* drawing command (such as MultiDrawElements or
|
||||
* MultiDrawArraysIndirect)."
|
||||
*
|
||||
* If GL_ARB_multi_draw_indirect is not supported, this is always 0.
|
||||
*/
|
||||
SYSTEM_VALUE_DRAW_ID,
|
||||
/*@}*/
|
||||
|
||||
/**
|
||||
* \name Geometry shader system values
|
||||
*/
|
||||
/*@{*/
|
||||
SYSTEM_VALUE_INVOCATION_ID, /**< (Also in Tessellation Control shader) */
|
||||
/*@}*/
|
||||
|
||||
/**
|
||||
* \name Fragment shader system values
|
||||
*/
|
||||
/*@{*/
|
||||
SYSTEM_VALUE_FRAG_COORD,
|
||||
SYSTEM_VALUE_POINT_COORD,
|
||||
SYSTEM_VALUE_FRONT_FACE,
|
||||
SYSTEM_VALUE_SAMPLE_ID,
|
||||
SYSTEM_VALUE_SAMPLE_POS,
|
||||
SYSTEM_VALUE_SAMPLE_MASK_IN,
|
||||
SYSTEM_VALUE_HELPER_INVOCATION,
|
||||
SYSTEM_VALUE_COLOR0,
|
||||
SYSTEM_VALUE_COLOR1,
|
||||
/*@}*/
|
||||
|
||||
/**
|
||||
* \name Tessellation Evaluation shader system values
|
||||
*/
|
||||
/*@{*/
|
||||
SYSTEM_VALUE_TESS_COORD,
|
||||
SYSTEM_VALUE_VERTICES_IN, /**< Tessellation vertices in input patch */
|
||||
SYSTEM_VALUE_PRIMITIVE_ID,
|
||||
SYSTEM_VALUE_TESS_LEVEL_OUTER, /**< TES input */
|
||||
SYSTEM_VALUE_TESS_LEVEL_INNER, /**< TES input */
|
||||
SYSTEM_VALUE_TESS_LEVEL_OUTER_DEFAULT, /**< TCS input for passthru TCS */
|
||||
SYSTEM_VALUE_TESS_LEVEL_INNER_DEFAULT, /**< TCS input for passthru TCS */
|
||||
/*@}*/
|
||||
|
||||
/**
|
||||
* \name Compute shader system values
|
||||
*/
|
||||
/*@{*/
|
||||
SYSTEM_VALUE_LOCAL_INVOCATION_ID,
|
||||
SYSTEM_VALUE_LOCAL_INVOCATION_INDEX,
|
||||
SYSTEM_VALUE_GLOBAL_INVOCATION_ID,
|
||||
SYSTEM_VALUE_GLOBAL_INVOCATION_INDEX,
|
||||
SYSTEM_VALUE_WORK_GROUP_ID,
|
||||
SYSTEM_VALUE_NUM_WORK_GROUPS,
|
||||
SYSTEM_VALUE_LOCAL_GROUP_SIZE,
|
||||
SYSTEM_VALUE_GLOBAL_GROUP_SIZE,
|
||||
SYSTEM_VALUE_WORK_DIM,
|
||||
SYSTEM_VALUE_USER_DATA_AMD,
|
||||
/*@}*/
|
||||
|
||||
/** Required for VK_KHR_device_group */
|
||||
SYSTEM_VALUE_DEVICE_INDEX,
|
||||
|
||||
/** Required for VK_KHX_multiview */
|
||||
SYSTEM_VALUE_VIEW_INDEX,
|
||||
|
||||
/**
|
||||
* Driver internal vertex-count, used (for example) for drivers to
|
||||
* calculate stride for stream-out outputs. Not externally visible.
|
||||
*/
|
||||
SYSTEM_VALUE_VERTEX_CNT,
|
||||
|
||||
/**
|
||||
* Required for AMD_shader_explicit_vertex_parameter and also used for
|
||||
* varying-fetch instructions.
|
||||
*
|
||||
* The _SIZE value is "primitive size", used to scale i/j in primitive
|
||||
* space to pixel space.
|
||||
*/
|
||||
SYSTEM_VALUE_BARYCENTRIC_PERSP_PIXEL,
|
||||
SYSTEM_VALUE_BARYCENTRIC_PERSP_SAMPLE,
|
||||
SYSTEM_VALUE_BARYCENTRIC_PERSP_CENTROID,
|
||||
SYSTEM_VALUE_BARYCENTRIC_PERSP_SIZE,
|
||||
SYSTEM_VALUE_BARYCENTRIC_LINEAR_PIXEL,
|
||||
SYSTEM_VALUE_BARYCENTRIC_LINEAR_CENTROID,
|
||||
SYSTEM_VALUE_BARYCENTRIC_LINEAR_SAMPLE,
|
||||
SYSTEM_VALUE_BARYCENTRIC_PULL_MODEL,
|
||||
|
||||
/**
|
||||
* IR3 specific geometry shader and tesselation control shader system
|
||||
* values that packs invocation id, thread id and vertex id. Having this
|
||||
* as a nir level system value lets us do the unpacking in nir.
|
||||
*/
|
||||
SYSTEM_VALUE_GS_HEADER_IR3,
|
||||
SYSTEM_VALUE_TCS_HEADER_IR3,
|
||||
|
||||
SYSTEM_VALUE_MAX /**< Number of values */
|
||||
} gl_system_value;
|
||||
|
||||
const char *gl_system_value_name(gl_system_value sysval);
|
||||
|
||||
/**
|
||||
* The possible interpolation qualifiers that can be applied to a fragment
|
||||
* shader input in GLSL.
|
||||
*
|
||||
* Note: INTERP_MODE_NONE must be 0 so that memsetting the
|
||||
* ir_variable data structure to 0 causes the default behavior.
|
||||
*/
|
||||
enum glsl_interp_mode
|
||||
{
|
||||
INTERP_MODE_NONE = 0,
|
||||
INTERP_MODE_SMOOTH,
|
||||
INTERP_MODE_FLAT,
|
||||
INTERP_MODE_NOPERSPECTIVE,
|
||||
INTERP_MODE_EXPLICIT,
|
||||
INTERP_MODE_COUNT /**< Number of interpolation qualifiers */
|
||||
};
|
||||
|
||||
enum glsl_interface_packing {
|
||||
GLSL_INTERFACE_PACKING_STD140,
|
||||
GLSL_INTERFACE_PACKING_SHARED,
|
||||
GLSL_INTERFACE_PACKING_PACKED,
|
||||
GLSL_INTERFACE_PACKING_STD430
|
||||
};
|
||||
|
||||
const char *glsl_interp_mode_name(enum glsl_interp_mode qual);
|
||||
|
||||
/**
|
||||
* Fragment program results
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
FRAG_RESULT_DEPTH = 0,
|
||||
FRAG_RESULT_STENCIL = 1,
|
||||
/* If a single color should be written to all render targets, this
|
||||
* register is written. No FRAG_RESULT_DATAn will be written.
|
||||
*/
|
||||
FRAG_RESULT_COLOR = 2,
|
||||
FRAG_RESULT_SAMPLE_MASK = 3,
|
||||
|
||||
/* FRAG_RESULT_DATAn are the per-render-target (GLSL gl_FragData[n]
|
||||
* or ARB_fragment_program fragment.color[n]) color results. If
|
||||
* any are written, FRAG_RESULT_COLOR will not be written.
|
||||
* FRAG_RESULT_DATA1 and up are simply for the benefit of
|
||||
* gl_frag_result_name() and not to be construed as an upper bound
|
||||
*/
|
||||
FRAG_RESULT_DATA0 = 4,
|
||||
FRAG_RESULT_DATA1,
|
||||
FRAG_RESULT_DATA2,
|
||||
FRAG_RESULT_DATA3,
|
||||
FRAG_RESULT_DATA4,
|
||||
FRAG_RESULT_DATA5,
|
||||
FRAG_RESULT_DATA6,
|
||||
FRAG_RESULT_DATA7,
|
||||
} gl_frag_result;
|
||||
|
||||
const char *gl_frag_result_name(gl_frag_result result);
|
||||
|
||||
#define FRAG_RESULT_MAX (FRAG_RESULT_DATA0 + MAX_DRAW_BUFFERS)
|
||||
|
||||
/**
|
||||
* \brief Layout qualifiers for gl_FragDepth.
|
||||
*
|
||||
* Extension AMD_conservative_depth allows gl_FragDepth to be redeclared with
|
||||
* a layout qualifier.
|
||||
*
|
||||
* \see enum ir_depth_layout
|
||||
*/
|
||||
enum gl_frag_depth_layout
|
||||
{
|
||||
FRAG_DEPTH_LAYOUT_NONE, /**< No layout is specified. */
|
||||
FRAG_DEPTH_LAYOUT_ANY,
|
||||
FRAG_DEPTH_LAYOUT_GREATER,
|
||||
FRAG_DEPTH_LAYOUT_LESS,
|
||||
FRAG_DEPTH_LAYOUT_UNCHANGED
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Buffer access qualifiers
|
||||
*/
|
||||
enum gl_access_qualifier
|
||||
{
|
||||
ACCESS_COHERENT = (1 << 0),
|
||||
ACCESS_RESTRICT = (1 << 1),
|
||||
ACCESS_VOLATILE = (1 << 2),
|
||||
ACCESS_NON_READABLE = (1 << 3),
|
||||
ACCESS_NON_WRITEABLE = (1 << 4),
|
||||
|
||||
/** The access may use a non-uniform buffer or image index */
|
||||
ACCESS_NON_UNIFORM = (1 << 5),
|
||||
|
||||
/* This has the same semantics as NIR_INTRINSIC_CAN_REORDER, only to be
|
||||
* used with loads. In other words, it means that the load can be
|
||||
* arbitrarily reordered, or combined with other loads to the same address.
|
||||
* It is implied by ACCESS_NON_WRITEABLE together with ACCESS_RESTRICT, and
|
||||
* a lack of ACCESS_COHERENT and ACCESS_VOLATILE.
|
||||
*/
|
||||
ACCESS_CAN_REORDER = (1 << 6),
|
||||
|
||||
/** Use as little cache space as possible. */
|
||||
ACCESS_STREAM_CACHE_POLICY = (1 << 7),
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Blend support qualifiers
|
||||
*/
|
||||
enum gl_advanced_blend_mode
|
||||
{
|
||||
BLEND_NONE = 0x0000,
|
||||
|
||||
BLEND_MULTIPLY = 0x0001,
|
||||
BLEND_SCREEN = 0x0002,
|
||||
BLEND_OVERLAY = 0x0004,
|
||||
BLEND_DARKEN = 0x0008,
|
||||
BLEND_LIGHTEN = 0x0010,
|
||||
BLEND_COLORDODGE = 0x0020,
|
||||
BLEND_COLORBURN = 0x0040,
|
||||
BLEND_HARDLIGHT = 0x0080,
|
||||
BLEND_SOFTLIGHT = 0x0100,
|
||||
BLEND_DIFFERENCE = 0x0200,
|
||||
BLEND_EXCLUSION = 0x0400,
|
||||
BLEND_HSL_HUE = 0x0800,
|
||||
BLEND_HSL_SATURATION = 0x1000,
|
||||
BLEND_HSL_COLOR = 0x2000,
|
||||
BLEND_HSL_LUMINOSITY = 0x4000,
|
||||
|
||||
BLEND_ALL = 0x7fff,
|
||||
};
|
||||
|
||||
enum blend_func
|
||||
{
|
||||
BLEND_FUNC_ADD,
|
||||
BLEND_FUNC_SUBTRACT,
|
||||
BLEND_FUNC_REVERSE_SUBTRACT,
|
||||
BLEND_FUNC_MIN,
|
||||
BLEND_FUNC_MAX,
|
||||
};
|
||||
|
||||
enum blend_factor
|
||||
{
|
||||
BLEND_FACTOR_ZERO,
|
||||
BLEND_FACTOR_SRC_COLOR,
|
||||
BLEND_FACTOR_DST_COLOR,
|
||||
BLEND_FACTOR_SRC_ALPHA,
|
||||
BLEND_FACTOR_DST_ALPHA,
|
||||
BLEND_FACTOR_CONSTANT_COLOR,
|
||||
BLEND_FACTOR_CONSTANT_ALPHA,
|
||||
BLEND_FACTOR_SRC_ALPHA_SATURATE,
|
||||
};
|
||||
|
||||
enum gl_tess_spacing
|
||||
{
|
||||
TESS_SPACING_UNSPECIFIED,
|
||||
TESS_SPACING_EQUAL,
|
||||
TESS_SPACING_FRACTIONAL_ODD,
|
||||
TESS_SPACING_FRACTIONAL_EVEN,
|
||||
};
|
||||
|
||||
/**
|
||||
* A compare function enum for use in compiler lowering passes. This is in
|
||||
* the same order as GL's compare functions (shifted down by GL_NEVER), and is
|
||||
* exactly the same as gallium's PIPE_FUNC_*.
|
||||
*/
|
||||
enum compare_func
|
||||
{
|
||||
COMPARE_FUNC_NEVER,
|
||||
COMPARE_FUNC_LESS,
|
||||
COMPARE_FUNC_EQUAL,
|
||||
COMPARE_FUNC_LEQUAL,
|
||||
COMPARE_FUNC_GREATER,
|
||||
COMPARE_FUNC_NOTEQUAL,
|
||||
COMPARE_FUNC_GEQUAL,
|
||||
COMPARE_FUNC_ALWAYS,
|
||||
};
|
||||
|
||||
/**
|
||||
* Arrangements for grouping invocations from NV_compute_shader_derivatives.
|
||||
*
|
||||
* The extension provides new layout qualifiers that support two different
|
||||
* arrangements of compute shader invocations for the purpose of derivative
|
||||
* computation. When specifying
|
||||
*
|
||||
* layout(derivative_group_quadsNV) in;
|
||||
*
|
||||
* compute shader invocations are grouped into 2x2x1 arrays whose four local
|
||||
* invocation ID values follow the pattern:
|
||||
*
|
||||
* +-----------------+------------------+
|
||||
* | (2x+0, 2y+0, z) | (2x+1, 2y+0, z) |
|
||||
* +-----------------+------------------+
|
||||
* | (2x+0, 2y+1, z) | (2x+1, 2y+1, z) |
|
||||
* +-----------------+------------------+
|
||||
*
|
||||
* where Y increases from bottom to top. When specifying
|
||||
*
|
||||
* layout(derivative_group_linearNV) in;
|
||||
*
|
||||
* compute shader invocations are grouped into 2x2x1 arrays whose four local
|
||||
* invocation index values follow the pattern:
|
||||
*
|
||||
* +------+------+
|
||||
* | 4n+0 | 4n+1 |
|
||||
* +------+------+
|
||||
* | 4n+2 | 4n+3 |
|
||||
* +------+------+
|
||||
*
|
||||
* If neither layout qualifier is specified, derivatives in compute shaders
|
||||
* return zero, which is consistent with the handling of built-in texture
|
||||
* functions like texture() in GLSL 4.50 compute shaders.
|
||||
*/
|
||||
enum gl_derivative_group {
|
||||
DERIVATIVE_GROUP_NONE = 0,
|
||||
DERIVATIVE_GROUP_QUADS,
|
||||
DERIVATIVE_GROUP_LINEAR,
|
||||
};
|
||||
|
||||
enum float_controls
|
||||
{
|
||||
FLOAT_CONTROLS_DEFAULT_FLOAT_CONTROL_MODE = 0x0000,
|
||||
FLOAT_CONTROLS_DENORM_PRESERVE_FP16 = 0x0001,
|
||||
FLOAT_CONTROLS_DENORM_PRESERVE_FP32 = 0x0002,
|
||||
FLOAT_CONTROLS_DENORM_PRESERVE_FP64 = 0x0004,
|
||||
FLOAT_CONTROLS_DENORM_FLUSH_TO_ZERO_FP16 = 0x0008,
|
||||
FLOAT_CONTROLS_DENORM_FLUSH_TO_ZERO_FP32 = 0x0010,
|
||||
FLOAT_CONTROLS_DENORM_FLUSH_TO_ZERO_FP64 = 0x0020,
|
||||
FLOAT_CONTROLS_SIGNED_ZERO_INF_NAN_PRESERVE_FP16 = 0x0040,
|
||||
FLOAT_CONTROLS_SIGNED_ZERO_INF_NAN_PRESERVE_FP32 = 0x0080,
|
||||
FLOAT_CONTROLS_SIGNED_ZERO_INF_NAN_PRESERVE_FP64 = 0x0100,
|
||||
FLOAT_CONTROLS_ROUNDING_MODE_RTE_FP16 = 0x0200,
|
||||
FLOAT_CONTROLS_ROUNDING_MODE_RTE_FP32 = 0x0400,
|
||||
FLOAT_CONTROLS_ROUNDING_MODE_RTE_FP64 = 0x0800,
|
||||
FLOAT_CONTROLS_ROUNDING_MODE_RTZ_FP16 = 0x1000,
|
||||
FLOAT_CONTROLS_ROUNDING_MODE_RTZ_FP32 = 0x2000,
|
||||
FLOAT_CONTROLS_ROUNDING_MODE_RTZ_FP64 = 0x4000,
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SHADER_ENUMS_H */
|
||||
@@ -1,326 +0,0 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright 2008 VMware, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sub license, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial portions
|
||||
* of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
|
||||
* IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
|
||||
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
|
||||
#ifndef BITSCAN_H
|
||||
#define BITSCAN_H
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
|
||||
#if defined(__POPCNT__)
|
||||
#include <popcntintrin.h>
|
||||
#endif
|
||||
|
||||
//#include "c99_compat.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Find first bit set in word. Least significant bit is 1.
|
||||
* Return 0 if no bits set.
|
||||
*/
|
||||
#ifdef HAVE___BUILTIN_FFS
|
||||
#define ffs __builtin_ffs
|
||||
#elif defined(_MSC_VER) && (_M_IX86 || _M_ARM || _M_AMD64 || _M_IA64)
|
||||
static inline
|
||||
int ffs(int i)
|
||||
{
|
||||
unsigned long index;
|
||||
if (_BitScanForward(&index, i))
|
||||
return index + 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
extern
|
||||
int ffs(int i);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE___BUILTIN_FFSLL
|
||||
#define ffsll __builtin_ffsll
|
||||
#elif defined(_MSC_VER) && (_M_AMD64 || _M_ARM64 || _M_IA64)
|
||||
static inline int
|
||||
ffsll(long long int i)
|
||||
{
|
||||
unsigned long index;
|
||||
if (_BitScanForward64(&index, i))
|
||||
return index + 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
extern int
|
||||
ffsll(long long int val);
|
||||
#endif
|
||||
|
||||
|
||||
/* Destructively loop over all of the bits in a mask as in:
|
||||
*
|
||||
* while (mymask) {
|
||||
* int i = u_bit_scan(&mymask);
|
||||
* ... process element i
|
||||
* }
|
||||
*
|
||||
*/
|
||||
static inline int
|
||||
u_bit_scan(unsigned *mask)
|
||||
{
|
||||
const int i = ffs(*mask) - 1;
|
||||
*mask ^= (1u << i);
|
||||
return i;
|
||||
}
|
||||
|
||||
static inline int
|
||||
u_bit_scan64(uint64_t *mask)
|
||||
{
|
||||
const int i = ffsll(*mask) - 1;
|
||||
*mask ^= (((uint64_t)1) << i);
|
||||
return i;
|
||||
}
|
||||
|
||||
/* Determine if an unsigned value is a power of two.
|
||||
*
|
||||
* \note
|
||||
* Zero is treated as a power of two.
|
||||
*/
|
||||
static inline bool
|
||||
util_is_power_of_two_or_zero(unsigned v)
|
||||
{
|
||||
return (v & (v - 1)) == 0;
|
||||
}
|
||||
|
||||
/* Determine if an uint64_t value is a power of two.
|
||||
*
|
||||
* \note
|
||||
* Zero is treated as a power of two.
|
||||
*/
|
||||
static inline bool
|
||||
util_is_power_of_two_or_zero64(uint64_t v)
|
||||
{
|
||||
return (v & (v - 1)) == 0;
|
||||
}
|
||||
|
||||
/* Determine if an unsigned value is a power of two.
|
||||
*
|
||||
* \note
|
||||
* Zero is \b not treated as a power of two.
|
||||
*/
|
||||
static inline bool
|
||||
util_is_power_of_two_nonzero(unsigned v)
|
||||
{
|
||||
/* __POPCNT__ is different from HAVE___BUILTIN_POPCOUNT. The latter
|
||||
* indicates the existence of the __builtin_popcount function. The former
|
||||
* indicates that _mm_popcnt_u32 exists and is a native instruction.
|
||||
*
|
||||
* The other alternative is to use SSE 4.2 compile-time flags. This has
|
||||
* two drawbacks. First, there is currently no build infrastructure for
|
||||
* SSE 4.2 (only 4.1), so that would have to be added. Second, some AMD
|
||||
* CPUs support POPCNT but not SSE 4.2 (e.g., Barcelona).
|
||||
*/
|
||||
#ifdef __POPCNT__
|
||||
return _mm_popcnt_u32(v) == 1;
|
||||
#else
|
||||
return v != 0 && (v & (v - 1)) == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* For looping over a bitmask when you want to loop over consecutive bits
|
||||
* manually, for example:
|
||||
*
|
||||
* while (mask) {
|
||||
* int start, count, i;
|
||||
*
|
||||
* u_bit_scan_consecutive_range(&mask, &start, &count);
|
||||
*
|
||||
* for (i = 0; i < count; i++)
|
||||
* ... process element (start+i)
|
||||
* }
|
||||
*/
|
||||
static inline void
|
||||
u_bit_scan_consecutive_range(unsigned *mask, int *start, int *count)
|
||||
{
|
||||
if (*mask == 0xffffffff) {
|
||||
*start = 0;
|
||||
*count = 32;
|
||||
*mask = 0;
|
||||
return;
|
||||
}
|
||||
*start = ffs(*mask) - 1;
|
||||
*count = ffs(~(*mask >> *start)) - 1;
|
||||
*mask &= ~(((1u << *count) - 1) << *start);
|
||||
}
|
||||
|
||||
static inline void
|
||||
u_bit_scan_consecutive_range64(uint64_t *mask, int *start, int *count)
|
||||
{
|
||||
if (*mask == ~0ull) {
|
||||
*start = 0;
|
||||
*count = 64;
|
||||
*mask = 0;
|
||||
return;
|
||||
}
|
||||
*start = ffsll(*mask) - 1;
|
||||
*count = ffsll(~(*mask >> *start)) - 1;
|
||||
*mask &= ~(((((uint64_t)1) << *count) - 1) << *start);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Find last bit set in a word. The least significant bit is 1.
|
||||
* Return 0 if no bits are set.
|
||||
* Essentially ffs() in the reverse direction.
|
||||
*/
|
||||
static inline unsigned
|
||||
util_last_bit(unsigned u)
|
||||
{
|
||||
#if defined(HAVE___BUILTIN_CLZ)
|
||||
return u == 0 ? 0 : 32 - __builtin_clz(u);
|
||||
#elif defined(_MSC_VER) && (_M_IX86 || _M_ARM || _M_AMD64 || _M_IA64)
|
||||
unsigned long index;
|
||||
if (_BitScanReverse(&index, u))
|
||||
return index + 1;
|
||||
else
|
||||
return 0;
|
||||
#else
|
||||
unsigned r = 0;
|
||||
while (u) {
|
||||
r++;
|
||||
u >>= 1;
|
||||
}
|
||||
return r;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Find last bit set in a word. The least significant bit is 1.
|
||||
* Return 0 if no bits are set.
|
||||
* Essentially ffsll() in the reverse direction.
|
||||
*/
|
||||
static inline unsigned
|
||||
util_last_bit64(uint64_t u)
|
||||
{
|
||||
#if defined(HAVE___BUILTIN_CLZLL)
|
||||
return u == 0 ? 0 : 64 - __builtin_clzll(u);
|
||||
#elif defined(_MSC_VER) && (_M_AMD64 || _M_ARM64 || _M_IA64)
|
||||
unsigned long index;
|
||||
if (_BitScanReverse64(&index, u))
|
||||
return index + 1;
|
||||
else
|
||||
return 0;
|
||||
#else
|
||||
unsigned r = 0;
|
||||
while (u) {
|
||||
r++;
|
||||
u >>= 1;
|
||||
}
|
||||
return r;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Find last bit in a word that does not match the sign bit. The least
|
||||
* significant bit is 1.
|
||||
* Return 0 if no bits are set.
|
||||
*/
|
||||
static inline unsigned
|
||||
util_last_bit_signed(int i)
|
||||
{
|
||||
if (i >= 0)
|
||||
return util_last_bit(i);
|
||||
else
|
||||
return util_last_bit(~(unsigned)i);
|
||||
}
|
||||
|
||||
/* Returns a bitfield in which the first count bits starting at start are
|
||||
* set.
|
||||
*/
|
||||
static inline unsigned
|
||||
u_bit_consecutive(unsigned start, unsigned count)
|
||||
{
|
||||
assert(start + count <= 32);
|
||||
if (count == 32)
|
||||
return ~0;
|
||||
return ((1u << count) - 1) << start;
|
||||
}
|
||||
|
||||
static inline uint64_t
|
||||
u_bit_consecutive64(unsigned start, unsigned count)
|
||||
{
|
||||
assert(start + count <= 64);
|
||||
if (count == 64)
|
||||
return ~(uint64_t)0;
|
||||
return (((uint64_t)1 << count) - 1) << start;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return number of bits set in n.
|
||||
*/
|
||||
static inline unsigned
|
||||
util_bitcount(unsigned n)
|
||||
{
|
||||
#if defined(HAVE___BUILTIN_POPCOUNT)
|
||||
return __builtin_popcount(n);
|
||||
#else
|
||||
/* K&R classic bitcount.
|
||||
*
|
||||
* For each iteration, clear the LSB from the bitfield.
|
||||
* Requires only one iteration per set bit, instead of
|
||||
* one iteration per bit less than highest set bit.
|
||||
*/
|
||||
unsigned bits;
|
||||
for (bits = 0; n; bits++) {
|
||||
n &= n - 1;
|
||||
}
|
||||
return bits;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline unsigned
|
||||
util_bitcount64(uint64_t n)
|
||||
{
|
||||
#ifdef HAVE___BUILTIN_POPCOUNTLL
|
||||
return __builtin_popcountll(n);
|
||||
#else
|
||||
return util_bitcount(n) + util_bitcount(n >> 32);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* BITSCAN_H */
|
||||
@@ -1,261 +0,0 @@
|
||||
/*
|
||||
* Mesa 3-D graphics library
|
||||
*
|
||||
* Copyright (C) 2006 Brian Paul All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file bitset.h
|
||||
* \brief Bitset of arbitrary size definitions.
|
||||
* \author Michal Krol
|
||||
*/
|
||||
|
||||
#ifndef BITSET_H
|
||||
#define BITSET_H
|
||||
|
||||
//#include "util/bitscan.h"
|
||||
//#include "util/macros.h"
|
||||
|
||||
/****************************************************************************
|
||||
* generic bitset implementation
|
||||
*/
|
||||
|
||||
#define BITSET_WORD unsigned int
|
||||
#define BITSET_WORDBITS (sizeof (BITSET_WORD) * 8)
|
||||
|
||||
/* bitset declarations
|
||||
*/
|
||||
#define BITSET_WORDS(bits) (((bits) + BITSET_WORDBITS - 1) / BITSET_WORDBITS)
|
||||
#define BITSET_DECLARE(name, bits) BITSET_WORD name[BITSET_WORDS(bits)]
|
||||
|
||||
/* bitset operations
|
||||
*/
|
||||
#define BITSET_COPY(x, y) memcpy( (x), (y), sizeof (x) )
|
||||
#define BITSET_EQUAL(x, y) (memcmp( (x), (y), sizeof (x) ) == 0)
|
||||
#define BITSET_ZERO(x) memset( (x), 0, sizeof (x) )
|
||||
#define BITSET_ONES(x) memset( (x), 0xff, sizeof (x) )
|
||||
|
||||
#define BITSET_BITWORD(b) ((b) / BITSET_WORDBITS)
|
||||
#define BITSET_BIT(b) (1u << ((b) % BITSET_WORDBITS))
|
||||
|
||||
/* single bit operations
|
||||
*/
|
||||
#define BITSET_TEST(x, b) (((x)[BITSET_BITWORD(b)] & BITSET_BIT(b)) != 0)
|
||||
#define BITSET_SET(x, b) ((x)[BITSET_BITWORD(b)] |= BITSET_BIT(b))
|
||||
#define BITSET_CLEAR(x, b) ((x)[BITSET_BITWORD(b)] &= ~BITSET_BIT(b))
|
||||
|
||||
#define BITSET_MASK(b) (((b) % BITSET_WORDBITS == 0) ? ~0 : BITSET_BIT(b) - 1)
|
||||
#define BITSET_RANGE(b, e) ((BITSET_MASK((e) + 1)) & ~(BITSET_BIT(b) - 1))
|
||||
|
||||
/* bit range operations
|
||||
*/
|
||||
#define BITSET_TEST_RANGE(x, b, e) \
|
||||
(BITSET_BITWORD(b) == BITSET_BITWORD(e) ? \
|
||||
(((x)[BITSET_BITWORD(b)] & BITSET_RANGE(b, e)) != 0) : \
|
||||
(assert (!"BITSET_TEST_RANGE: bit range crosses word boundary"), 0))
|
||||
#define BITSET_SET_RANGE(x, b, e) \
|
||||
(BITSET_BITWORD(b) == BITSET_BITWORD(e) ? \
|
||||
((x)[BITSET_BITWORD(b)] |= BITSET_RANGE(b, e)) : \
|
||||
(assert (!"BITSET_SET_RANGE: bit range crosses word boundary"), 0))
|
||||
#define BITSET_CLEAR_RANGE(x, b, e) \
|
||||
(BITSET_BITWORD(b) == BITSET_BITWORD(e) ? \
|
||||
((x)[BITSET_BITWORD(b)] &= ~BITSET_RANGE(b, e)) : \
|
||||
(assert (!"BITSET_CLEAR_RANGE: bit range crosses word boundary"), 0))
|
||||
|
||||
/* Get first bit set in a bitset.
|
||||
*/
|
||||
static inline int
|
||||
__bitset_ffs(const BITSET_WORD *x, int n)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
if (x[i])
|
||||
return ffs(x[i]) + BITSET_WORDBITS * i;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define BITSET_FFS(x) __bitset_ffs(x, ARRAY_SIZE(x))
|
||||
|
||||
static inline unsigned
|
||||
__bitset_next_set(unsigned i, BITSET_WORD *tmp,
|
||||
const BITSET_WORD *set, unsigned size)
|
||||
{
|
||||
unsigned bit, word;
|
||||
|
||||
/* NOTE: The initial conditions for this function are very specific. At
|
||||
* the start of the loop, the tmp variable must be set to *set and the
|
||||
* initial i value set to 0. This way, if there is a bit set in the first
|
||||
* word, we ignore the i-value and just grab that bit (so 0 is ok, even
|
||||
* though 0 may be returned). If the first word is 0, then the value of
|
||||
* `word` will be 0 and we will go on to look at the second word.
|
||||
*/
|
||||
word = BITSET_BITWORD(i);
|
||||
while (*tmp == 0) {
|
||||
word++;
|
||||
|
||||
if (word >= BITSET_WORDS(size))
|
||||
return size;
|
||||
|
||||
*tmp = set[word];
|
||||
}
|
||||
|
||||
/* Find the next set bit in the non-zero word */
|
||||
bit = ffs(*tmp) - 1;
|
||||
|
||||
/* Unset the bit */
|
||||
*tmp &= ~(1ull << bit);
|
||||
|
||||
return word * BITSET_WORDBITS + bit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates over each set bit in a set
|
||||
*
|
||||
* @param __i iteration variable, bit number
|
||||
* @param __set the bitset to iterate (will not be modified)
|
||||
* @param __size number of bits in the set to consider
|
||||
*/
|
||||
#define BITSET_FOREACH_SET(__i, __set, __size) \
|
||||
for (BITSET_WORD __tmp = *(__set), *__foo = &__tmp; __foo != NULL; __foo = NULL) \
|
||||
for (__i = 0; \
|
||||
(__i = __bitset_next_set(__i, &__tmp, __set, __size)) < __size;)
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
/**
|
||||
* Simple C++ wrapper of a bitset type of static size, with value semantics
|
||||
* and basic bitwise arithmetic operators. The operators defined below are
|
||||
* expected to have the same semantics as the same operator applied to other
|
||||
* fundamental integer types. T is the name of the struct to instantiate
|
||||
* it as, and N is the number of bits in the bitset.
|
||||
*/
|
||||
#define DECLARE_BITSET_T(T, N) struct T { \
|
||||
EXPLICIT_CONVERSION \
|
||||
operator bool() const \
|
||||
{ \
|
||||
for (unsigned i = 0; i < BITSET_WORDS(N); i++) \
|
||||
if (words[i]) \
|
||||
return true; \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
T & \
|
||||
operator=(int x) \
|
||||
{ \
|
||||
const T c = {{ (BITSET_WORD)x }}; \
|
||||
return *this = c; \
|
||||
} \
|
||||
\
|
||||
friend bool \
|
||||
operator==(const T &b, const T &c) \
|
||||
{ \
|
||||
return BITSET_EQUAL(b.words, c.words); \
|
||||
} \
|
||||
\
|
||||
friend bool \
|
||||
operator!=(const T &b, const T &c) \
|
||||
{ \
|
||||
return !(b == c); \
|
||||
} \
|
||||
\
|
||||
friend bool \
|
||||
operator==(const T &b, int x) \
|
||||
{ \
|
||||
const T c = {{ (BITSET_WORD)x }}; \
|
||||
return b == c; \
|
||||
} \
|
||||
\
|
||||
friend bool \
|
||||
operator!=(const T &b, int x) \
|
||||
{ \
|
||||
return !(b == x); \
|
||||
} \
|
||||
\
|
||||
friend T \
|
||||
operator~(const T &b) \
|
||||
{ \
|
||||
T c; \
|
||||
for (unsigned i = 0; i < BITSET_WORDS(N); i++) \
|
||||
c.words[i] = ~b.words[i]; \
|
||||
return c; \
|
||||
} \
|
||||
\
|
||||
T & \
|
||||
operator|=(const T &b) \
|
||||
{ \
|
||||
for (unsigned i = 0; i < BITSET_WORDS(N); i++) \
|
||||
words[i] |= b.words[i]; \
|
||||
return *this; \
|
||||
} \
|
||||
\
|
||||
friend T \
|
||||
operator|(const T &b, const T &c) \
|
||||
{ \
|
||||
T d = b; \
|
||||
d |= c; \
|
||||
return d; \
|
||||
} \
|
||||
\
|
||||
T & \
|
||||
operator&=(const T &b) \
|
||||
{ \
|
||||
for (unsigned i = 0; i < BITSET_WORDS(N); i++) \
|
||||
words[i] &= b.words[i]; \
|
||||
return *this; \
|
||||
} \
|
||||
\
|
||||
friend T \
|
||||
operator&(const T &b, const T &c) \
|
||||
{ \
|
||||
T d = b; \
|
||||
d &= c; \
|
||||
return d; \
|
||||
} \
|
||||
\
|
||||
bool \
|
||||
test(unsigned i) const \
|
||||
{ \
|
||||
return BITSET_TEST(words, i); \
|
||||
} \
|
||||
\
|
||||
T & \
|
||||
set(unsigned i) \
|
||||
{ \
|
||||
BITSET_SET(words, i); \
|
||||
return *this; \
|
||||
} \
|
||||
\
|
||||
T & \
|
||||
clear(unsigned i) \
|
||||
{ \
|
||||
BITSET_CLEAR(words, i); \
|
||||
return *this; \
|
||||
} \
|
||||
\
|
||||
BITSET_WORD words[BITSET_WORDS(N)]; \
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,262 +0,0 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright 2006 VMware, Inc., Bismarck, ND. USA.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sub license, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
* USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial portions
|
||||
* of the Software.
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
/**
|
||||
* \file
|
||||
* List macros heavily inspired by the Linux kernel
|
||||
* list handling. No list looping yet.
|
||||
*
|
||||
* Is not threadsafe, so common operations need to
|
||||
* be protected using an external mutex.
|
||||
*/
|
||||
|
||||
#ifndef _UTIL_LIST_H_
|
||||
#define _UTIL_LIST_H_
|
||||
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef DEBUG
|
||||
# define list_assert(cond, msg) assert(cond && msg)
|
||||
#else
|
||||
# define list_assert(cond, msg) (void)(0 && (cond))
|
||||
#endif
|
||||
|
||||
struct list_head
|
||||
{
|
||||
struct list_head *prev;
|
||||
struct list_head *next;
|
||||
};
|
||||
|
||||
static inline void list_inithead(struct list_head *item)
|
||||
{
|
||||
item->prev = item;
|
||||
item->next = item;
|
||||
}
|
||||
|
||||
static inline void list_add(struct list_head *item, struct list_head *list)
|
||||
{
|
||||
item->prev = list;
|
||||
item->next = list->next;
|
||||
list->next->prev = item;
|
||||
list->next = item;
|
||||
}
|
||||
|
||||
static inline void list_addtail(struct list_head *item, struct list_head *list)
|
||||
{
|
||||
item->next = list;
|
||||
item->prev = list->prev;
|
||||
list->prev->next = item;
|
||||
list->prev = item;
|
||||
}
|
||||
|
||||
static inline bool list_is_empty(const struct list_head *list);
|
||||
|
||||
static inline void list_replace(struct list_head *from, struct list_head *to)
|
||||
{
|
||||
if (list_is_empty(from)) {
|
||||
list_inithead(to);
|
||||
} else {
|
||||
to->prev = from->prev;
|
||||
to->next = from->next;
|
||||
from->next->prev = to;
|
||||
from->prev->next = to;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void list_del(struct list_head *item)
|
||||
{
|
||||
item->prev->next = item->next;
|
||||
item->next->prev = item->prev;
|
||||
item->prev = item->next = NULL;
|
||||
}
|
||||
|
||||
static inline void list_delinit(struct list_head *item)
|
||||
{
|
||||
item->prev->next = item->next;
|
||||
item->next->prev = item->prev;
|
||||
item->next = item;
|
||||
item->prev = item;
|
||||
}
|
||||
|
||||
static inline bool list_is_empty(const struct list_head *list)
|
||||
{
|
||||
return list->next == list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the list has exactly one element.
|
||||
*/
|
||||
static inline bool list_is_singular(const struct list_head *list)
|
||||
{
|
||||
return list->next != NULL && list->next != list && list->next->next == list;
|
||||
}
|
||||
|
||||
static inline unsigned list_length(const struct list_head *list)
|
||||
{
|
||||
struct list_head *node;
|
||||
unsigned length = 0;
|
||||
for (node = list->next; node != list; node = node->next)
|
||||
length++;
|
||||
return length;
|
||||
}
|
||||
|
||||
static inline void list_splice(struct list_head *src, struct list_head *dst)
|
||||
{
|
||||
if (list_is_empty(src))
|
||||
return;
|
||||
|
||||
src->next->prev = dst;
|
||||
src->prev->next = dst->next;
|
||||
dst->next->prev = src->prev;
|
||||
dst->next = src->next;
|
||||
}
|
||||
|
||||
static inline void list_splicetail(struct list_head *src, struct list_head *dst)
|
||||
{
|
||||
if (list_is_empty(src))
|
||||
return;
|
||||
|
||||
src->prev->next = dst;
|
||||
src->next->prev = dst->prev;
|
||||
dst->prev->next = src->next;
|
||||
dst->prev = src->prev;
|
||||
}
|
||||
|
||||
static inline void list_validate(const struct list_head *list)
|
||||
{
|
||||
struct list_head *node;
|
||||
assert(list->next->prev == list && list->prev->next == list);
|
||||
for (node = list->next; node != list; node = node->next)
|
||||
assert(node->next->prev == node && node->prev->next == node);
|
||||
}
|
||||
|
||||
#define LIST_ENTRY(__type, __item, __field) \
|
||||
((__type *)(((char *)(__item)) - offsetof(__type, __field)))
|
||||
|
||||
/**
|
||||
* Cast from a pointer to a member of a struct back to the containing struct.
|
||||
*
|
||||
* 'sample' MUST be initialized, or else the result is undefined!
|
||||
*/
|
||||
#ifndef container_of
|
||||
#define container_of(ptr, sample, member) \
|
||||
(void *)((char *)(ptr) \
|
||||
- ((char *)&(sample)->member - (char *)(sample)))
|
||||
#endif
|
||||
|
||||
#define list_first_entry(ptr, type, member) \
|
||||
LIST_ENTRY(type, (ptr)->next, member)
|
||||
|
||||
#define list_last_entry(ptr, type, member) \
|
||||
LIST_ENTRY(type, (ptr)->prev, member)
|
||||
|
||||
|
||||
#define LIST_FOR_EACH_ENTRY(pos, head, member) \
|
||||
for (pos = NULL, pos = container_of((head)->next, pos, member); \
|
||||
&pos->member != (head); \
|
||||
pos = container_of(pos->member.next, pos, member))
|
||||
|
||||
#define LIST_FOR_EACH_ENTRY_SAFE(pos, storage, head, member) \
|
||||
for (pos = NULL, pos = container_of((head)->next, pos, member), \
|
||||
storage = container_of(pos->member.next, pos, member); \
|
||||
&pos->member != (head); \
|
||||
pos = storage, storage = container_of(storage->member.next, storage, member))
|
||||
|
||||
#define LIST_FOR_EACH_ENTRY_SAFE_REV(pos, storage, head, member) \
|
||||
for (pos = NULL, pos = container_of((head)->prev, pos, member), \
|
||||
storage = container_of(pos->member.prev, pos, member); \
|
||||
&pos->member != (head); \
|
||||
pos = storage, storage = container_of(storage->member.prev, storage, member))
|
||||
|
||||
#define LIST_FOR_EACH_ENTRY_FROM(pos, start, head, member) \
|
||||
for (pos = NULL, pos = container_of((start), pos, member); \
|
||||
&pos->member != (head); \
|
||||
pos = container_of(pos->member.next, pos, member))
|
||||
|
||||
#define LIST_FOR_EACH_ENTRY_FROM_REV(pos, start, head, member) \
|
||||
for (pos = NULL, pos = container_of((start), pos, member); \
|
||||
&pos->member != (head); \
|
||||
pos = container_of(pos->member.prev, pos, member))
|
||||
|
||||
#define list_for_each_entry(type, pos, head, member) \
|
||||
for (type *pos = LIST_ENTRY(type, (head)->next, member), \
|
||||
*__next = LIST_ENTRY(type, pos->member.next, member); \
|
||||
&pos->member != (head); \
|
||||
pos = LIST_ENTRY(type, pos->member.next, member), \
|
||||
list_assert(pos == __next, "use _safe iterator"), \
|
||||
__next = LIST_ENTRY(type, __next->member.next, member))
|
||||
|
||||
#define list_for_each_entry_safe(type, pos, head, member) \
|
||||
for (type *pos = LIST_ENTRY(type, (head)->next, member), \
|
||||
*__next = LIST_ENTRY(type, pos->member.next, member); \
|
||||
&pos->member != (head); \
|
||||
pos = __next, \
|
||||
__next = LIST_ENTRY(type, __next->member.next, member))
|
||||
|
||||
#define list_for_each_entry_rev(type, pos, head, member) \
|
||||
for (type *pos = LIST_ENTRY(type, (head)->prev, member), \
|
||||
*__prev = LIST_ENTRY(type, pos->member.prev, member); \
|
||||
&pos->member != (head); \
|
||||
pos = LIST_ENTRY(type, pos->member.prev, member), \
|
||||
list_assert(pos == __prev, "use _safe iterator"), \
|
||||
__prev = LIST_ENTRY(type, __prev->member.prev, member))
|
||||
|
||||
#define list_for_each_entry_safe_rev(type, pos, head, member) \
|
||||
for (type *pos = LIST_ENTRY(type, (head)->prev, member), \
|
||||
*__prev = LIST_ENTRY(type, pos->member.prev, member); \
|
||||
&pos->member != (head); \
|
||||
pos = __prev, \
|
||||
__prev = LIST_ENTRY(type, __prev->member.prev, member))
|
||||
|
||||
#define list_for_each_entry_from(type, pos, start, head, member) \
|
||||
for (type *pos = LIST_ENTRY(type, (start), member); \
|
||||
&pos->member != (head); \
|
||||
pos = LIST_ENTRY(type, pos->member.next, member))
|
||||
|
||||
#define list_for_each_entry_from_safe(type, pos, start, head, member) \
|
||||
for (type *pos = LIST_ENTRY(type, (start), member), \
|
||||
*__next = LIST_ENTRY(type, pos->member.next, member); \
|
||||
&pos->member != (head); \
|
||||
pos = __next, \
|
||||
__next = LIST_ENTRY(type, __next->member.next, member))
|
||||
|
||||
#define list_for_each_entry_from_rev(type, pos, start, head, member) \
|
||||
for (type *pos = LIST_ENTRY(type, (start), member); \
|
||||
&pos->member != (head); \
|
||||
pos = LIST_ENTRY(type, pos->member.prev, member))
|
||||
|
||||
#define list_pair_for_each_entry(type, pos1, pos2, head1, head2, member) \
|
||||
for (type *pos1 = LIST_ENTRY(type, (head1)->next, member), \
|
||||
*pos2 = LIST_ENTRY(type, (head2)->next, member); \
|
||||
&pos1->member != (head1) && &pos2->member != (head2); \
|
||||
pos1 = LIST_ENTRY(type, pos1->member.next, member), \
|
||||
pos2 = LIST_ENTRY(type, pos2->member.next, member))
|
||||
|
||||
#endif /*_UTIL_LIST_H_*/
|
||||
@@ -1,346 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2014 Intel Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef UTIL_MACROS_H
|
||||
#define UTIL_MACROS_H
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
/* Compute the size of an array */
|
||||
#ifndef ARRAY_SIZE
|
||||
# define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
|
||||
#endif
|
||||
|
||||
/* For compatibility with Clang's __has_builtin() */
|
||||
#ifndef __has_builtin
|
||||
# define __has_builtin(x) 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* __builtin_expect macros
|
||||
*/
|
||||
#if !defined(HAVE___BUILTIN_EXPECT)
|
||||
# define __builtin_expect(x, y) (x)
|
||||
#endif
|
||||
|
||||
#ifndef likely
|
||||
# ifdef HAVE___BUILTIN_EXPECT
|
||||
# define likely(x) __builtin_expect(!!(x), 1)
|
||||
# define unlikely(x) __builtin_expect(!!(x), 0)
|
||||
# else
|
||||
# define likely(x) (x)
|
||||
# define unlikely(x) (x)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Static (compile-time) assertion.
|
||||
* Basically, use COND to dimension an array. If COND is false/zero the
|
||||
* array size will be -1 and we'll get a compilation error.
|
||||
*/
|
||||
#define STATIC_ASSERT(COND) \
|
||||
do { \
|
||||
(void) sizeof(char [1 - 2*!(COND)]); \
|
||||
} while (0)
|
||||
|
||||
|
||||
/**
|
||||
* Unreachable macro. Useful for suppressing "control reaches end of non-void
|
||||
* function" warnings.
|
||||
*/
|
||||
#if defined(HAVE___BUILTIN_UNREACHABLE) || __has_builtin(__builtin_unreachable)
|
||||
#define unreachable(str) \
|
||||
do { \
|
||||
assert(!str); \
|
||||
__builtin_unreachable(); \
|
||||
} while (0)
|
||||
#elif defined (_MSC_VER)
|
||||
#define unreachable(str) \
|
||||
do { \
|
||||
assert(!str); \
|
||||
__assume(0); \
|
||||
} while (0)
|
||||
#else
|
||||
#define unreachable(str) assert(!str)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Assume macro. Useful for expressing our assumptions to the compiler,
|
||||
* typically for purposes of silencing warnings.
|
||||
*/
|
||||
#if __has_builtin(__builtin_assume)
|
||||
#define assume(expr) \
|
||||
do { \
|
||||
assert(expr); \
|
||||
__builtin_assume(expr); \
|
||||
} while (0)
|
||||
#elif defined HAVE___BUILTIN_UNREACHABLE
|
||||
#define assume(expr) ((expr) ? ((void) 0) \
|
||||
: (assert(!"assumption failed"), \
|
||||
__builtin_unreachable()))
|
||||
#elif defined (_MSC_VER)
|
||||
#define assume(expr) __assume(expr)
|
||||
#else
|
||||
#define assume(expr) assert(expr)
|
||||
#endif
|
||||
|
||||
/* Attribute const is used for functions that have no effects other than their
|
||||
* return value, and only rely on the argument values to compute the return
|
||||
* value. As a result, calls to it can be CSEed. Note that using memory
|
||||
* pointed to by the arguments is not allowed for const functions.
|
||||
*/
|
||||
#ifdef HAVE_FUNC_ATTRIBUTE_CONST
|
||||
#define ATTRIBUTE_CONST __attribute__((__const__))
|
||||
#else
|
||||
#define ATTRIBUTE_CONST
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_FUNC_ATTRIBUTE_FLATTEN
|
||||
#define FLATTEN __attribute__((__flatten__))
|
||||
#else
|
||||
#define FLATTEN
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_FUNC_ATTRIBUTE_FORMAT
|
||||
#define PRINTFLIKE(f, a) __attribute__ ((format(__printf__, f, a)))
|
||||
#else
|
||||
#define PRINTFLIKE(f, a)
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_FUNC_ATTRIBUTE_MALLOC
|
||||
#define MALLOCLIKE __attribute__((__malloc__))
|
||||
#else
|
||||
#define MALLOCLIKE
|
||||
#endif
|
||||
|
||||
/* Forced function inlining */
|
||||
/* Note: Clang also sets __GNUC__ (see other cases below) */
|
||||
#ifndef ALWAYS_INLINE
|
||||
# if defined(__GNUC__)
|
||||
# define ALWAYS_INLINE inline __attribute__((always_inline))
|
||||
# elif defined(_MSC_VER)
|
||||
# define ALWAYS_INLINE __forceinline
|
||||
# else
|
||||
# define ALWAYS_INLINE inline
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Used to optionally mark structures with misaligned elements or size as
|
||||
* packed, to trade off performance for space.
|
||||
*/
|
||||
#ifdef HAVE_FUNC_ATTRIBUTE_PACKED
|
||||
#define PACKED __attribute__((__packed__))
|
||||
#else
|
||||
#define PACKED
|
||||
#endif
|
||||
|
||||
/* Attribute pure is used for functions that have no effects other than their
|
||||
* return value. As a result, calls to it can be dead code eliminated.
|
||||
*/
|
||||
#ifdef HAVE_FUNC_ATTRIBUTE_PURE
|
||||
#define ATTRIBUTE_PURE __attribute__((__pure__))
|
||||
#else
|
||||
#define ATTRIBUTE_PURE
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_FUNC_ATTRIBUTE_RETURNS_NONNULL
|
||||
#define ATTRIBUTE_RETURNS_NONNULL __attribute__((__returns_nonnull__))
|
||||
#else
|
||||
#define ATTRIBUTE_RETURNS_NONNULL
|
||||
#endif
|
||||
|
||||
#ifndef NORETURN
|
||||
# ifdef _MSC_VER
|
||||
# define NORETURN __declspec(noreturn)
|
||||
# elif defined HAVE_FUNC_ATTRIBUTE_NORETURN
|
||||
# define NORETURN __attribute__((__noreturn__))
|
||||
# else
|
||||
# define NORETURN
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
/**
|
||||
* Macro function that evaluates to true if T is a trivially
|
||||
* destructible type -- that is, if its (non-virtual) destructor
|
||||
* performs no action and all member variables and base classes are
|
||||
* trivially destructible themselves.
|
||||
*/
|
||||
# if (defined(__clang__) && defined(__has_feature))
|
||||
# if __has_feature(has_trivial_destructor)
|
||||
# define HAS_TRIVIAL_DESTRUCTOR(T) __has_trivial_destructor(T)
|
||||
# endif
|
||||
# elif defined(__GNUC__)
|
||||
# if ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)))
|
||||
# define HAS_TRIVIAL_DESTRUCTOR(T) __has_trivial_destructor(T)
|
||||
# endif
|
||||
# elif defined(_MSC_VER) && !defined(__INTEL_COMPILER)
|
||||
# define HAS_TRIVIAL_DESTRUCTOR(T) __has_trivial_destructor(T)
|
||||
# endif
|
||||
# ifndef HAS_TRIVIAL_DESTRUCTOR
|
||||
/* It's always safe (if inefficient) to assume that a
|
||||
* destructor is non-trivial.
|
||||
*/
|
||||
# define HAS_TRIVIAL_DESTRUCTOR(T) (false)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* PUBLIC/USED macros
|
||||
*
|
||||
* If we build the library with gcc's -fvisibility=hidden flag, we'll
|
||||
* use the PUBLIC macro to mark functions that are to be exported.
|
||||
*
|
||||
* We also need to define a USED attribute, so the optimizer doesn't
|
||||
* inline a static function that we later use in an alias. - ajax
|
||||
*/
|
||||
#ifndef PUBLIC
|
||||
# if defined(__GNUC__)
|
||||
# define PUBLIC __attribute__((visibility("default")))
|
||||
# define USED __attribute__((used))
|
||||
# elif defined(_MSC_VER)
|
||||
# define PUBLIC __declspec(dllexport)
|
||||
# define USED
|
||||
# else
|
||||
# define PUBLIC
|
||||
# define USED
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* UNUSED marks variables (or sometimes functions) that have to be defined,
|
||||
* but are sometimes (or always) unused beyond that. A common case is for
|
||||
* a function parameter to be used in some build configurations but not others.
|
||||
* Another case is fallback vfuncs that don't do anything with their params.
|
||||
*
|
||||
* Note that this should not be used for identifiers used in `assert()`;
|
||||
* see ASSERTED below.
|
||||
*/
|
||||
#ifdef HAVE_FUNC_ATTRIBUTE_UNUSED
|
||||
#define UNUSED __attribute__((unused))
|
||||
#else
|
||||
#define UNUSED
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Use ASSERTED to indicate that an identifier is unused outside of an `assert()`,
|
||||
* so that assert-free builds don't get "unused variable" warnings.
|
||||
*/
|
||||
#ifdef NDEBUG
|
||||
#define ASSERTED UNUSED
|
||||
#else
|
||||
#define ASSERTED
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_FUNC_ATTRIBUTE_WARN_UNUSED_RESULT
|
||||
#define MUST_CHECK __attribute__((warn_unused_result))
|
||||
#else
|
||||
#define MUST_CHECK
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#define ATTRIBUTE_NOINLINE __attribute__((noinline))
|
||||
#else
|
||||
#define ATTRIBUTE_NOINLINE
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Check that STRUCT::FIELD can hold MAXVAL. We use a lot of bitfields
|
||||
* in Mesa/gallium. We have to be sure they're of sufficient size to
|
||||
* hold the largest expected value.
|
||||
* Note that with MSVC, enums are signed and enum bitfields need one extra
|
||||
* high bit (always zero) to ensure the max value is handled correctly.
|
||||
* This macro will detect that with MSVC, but not GCC.
|
||||
*/
|
||||
#define ASSERT_BITFIELD_SIZE(STRUCT, FIELD, MAXVAL) \
|
||||
do { \
|
||||
ASSERTED STRUCT s; \
|
||||
s.FIELD = (MAXVAL); \
|
||||
assert((int) s.FIELD == (MAXVAL) && "Insufficient bitfield size!"); \
|
||||
} while (0)
|
||||
|
||||
|
||||
/** Compute ceiling of integer quotient of A divided by B. */
|
||||
#define DIV_ROUND_UP( A, B ) ( ((A) + (B) - 1) / (B) )
|
||||
|
||||
/** Clamp X to [MIN,MAX]. Turn NaN into MIN, arbitrarily. */
|
||||
#define CLAMP( X, MIN, MAX ) ( (X)>(MIN) ? ((X)>(MAX) ? (MAX) : (X)) : (MIN) )
|
||||
|
||||
/** Minimum of two values: */
|
||||
#define MIN2( A, B ) ( (A)<(B) ? (A) : (B) )
|
||||
|
||||
/** Maximum of two values: */
|
||||
#define MAX2( A, B ) ( (A)>(B) ? (A) : (B) )
|
||||
|
||||
/** Minimum and maximum of three values: */
|
||||
#define MIN3( A, B, C ) ((A) < (B) ? MIN2(A, C) : MIN2(B, C))
|
||||
#define MAX3( A, B, C ) ((A) > (B) ? MAX2(A, C) : MAX2(B, C))
|
||||
|
||||
/** Align a value to a power of two */
|
||||
#define ALIGN_POT(x, pot_align) (((x) + (pot_align) - 1) & ~((pot_align) - 1))
|
||||
|
||||
/**
|
||||
* Macro for declaring an explicit conversion operator. Defaults to an
|
||||
* implicit conversion if C++11 is not supported.
|
||||
*/
|
||||
#if __cplusplus >= 201103L
|
||||
#define EXPLICIT_CONVERSION explicit
|
||||
#elif defined(__cplusplus)
|
||||
#define EXPLICIT_CONVERSION
|
||||
#endif
|
||||
|
||||
/** Set a single bit */
|
||||
#define BITFIELD_BIT(b) (1u << (b))
|
||||
/** Set all bits up to excluding bit b */
|
||||
#define BITFIELD_MASK(b) \
|
||||
((b) == 32 ? (~0u) : BITFIELD_BIT((b) % 32) - 1)
|
||||
/** Set count bits starting from bit b */
|
||||
#define BITFIELD_RANGE(b, count) \
|
||||
(BITFIELD_MASK((b) + (count)) & ~BITFIELD_MASK(b))
|
||||
|
||||
/** Set a single bit */
|
||||
#define BITFIELD64_BIT(b) (1ull << (b))
|
||||
/** Set all bits up to excluding bit b */
|
||||
#define BITFIELD64_MASK(b) \
|
||||
((b) == 64 ? (~0ull) : BITFIELD64_BIT(b) - 1)
|
||||
/** Set count bits starting from bit b */
|
||||
#define BITFIELD64_RANGE(b, count) \
|
||||
(BITFIELD64_MASK((b) + (count)) & ~BITFIELD64_MASK(b))
|
||||
|
||||
/* TODO: In future we should try to move this to u_debug.h once header
|
||||
* dependencies are reorganised to allow this.
|
||||
*/
|
||||
enum pipe_debug_type
|
||||
{
|
||||
PIPE_DEBUG_TYPE_OUT_OF_MEMORY = 1,
|
||||
PIPE_DEBUG_TYPE_ERROR,
|
||||
PIPE_DEBUG_TYPE_SHADER_INFO,
|
||||
PIPE_DEBUG_TYPE_PERF_INFO,
|
||||
PIPE_DEBUG_TYPE_INFO,
|
||||
PIPE_DEBUG_TYPE_FALLBACK,
|
||||
PIPE_DEBUG_TYPE_CONFORMANCE,
|
||||
};
|
||||
|
||||
#endif /* UTIL_MACROS_H */
|
||||
@@ -1,37 +0,0 @@
|
||||
# Welcome to the tinygrad documentation!
|
||||
|
||||
Here you will find documentation for tinygrad, as well as some examples and tutorials.
|
||||
|
||||
## Getting Started
|
||||
|
||||
Read the quick start guide [here](/docs/quickstart.md).
|
||||
|
||||
Or if you want to jump right in to how tinygrad works, you can read the [abstraction stack](/docs/abstractions.py) documentation.
|
||||
|
||||
Or if you want to see some examples, you can look at the examples in the [examples](/examples) directory.
|
||||
|
||||
Or if you just want to see some of the things tinygrad can do, check out the [showcase](/docs/showcase.md).
|
||||
|
||||
## API
|
||||
|
||||
This is currently a big work in progress.
|
||||
|
||||
## Resources
|
||||
|
||||
### Environment Variables
|
||||
|
||||
[env_vars.md](/docs/env_vars.md)
|
||||
|
||||
### Adding New Accelerators
|
||||
|
||||
[adding_new_accelerators.md](/docs/adding_new_accelerators.md)
|
||||
|
||||
### Community
|
||||
|
||||
[](https://discord.gg/ZjZadyC7PK)
|
||||
|
||||
## Contributing
|
||||
|
||||
The documentation mainly follows the core contributing guidelines in the [README.md](/README.md#contributing).
|
||||
|
||||
Additionally, we always welcome documentation contributions, especially for features that are currently under documented.
|
||||
@@ -1,407 +0,0 @@
|
||||
"""
|
||||
Welcome to the tinygrad documentation
|
||||
=================
|
||||
|
||||
this file will take you on a whirlwind journey from a Tensor all the way down
|
||||
tinygrad has been aggressively refactored in the 2.5 years it's been worked on.
|
||||
what you see here is a refined library (with more refining to go still!)
|
||||
|
||||
the whole tinygrad is ~2300 lines, so while it's readable in an evening or two,
|
||||
this documentation will help with entry points and understanding the abstraction stack
|
||||
"""
|
||||
|
||||
# %%
|
||||
# == Boilerplate imports for typing ==
|
||||
from __future__ import annotations
|
||||
from typing import Optional, Tuple, Union, Any, Dict, Callable, Type, List, ClassVar
|
||||
from enum import Enum, auto
|
||||
from abc import ABC
|
||||
|
||||
# %%
|
||||
# == Example: Tensor 2+3 ==
|
||||
# let's trace an addition down through the layers of abstraction.
|
||||
|
||||
# we will be using the clang backend
|
||||
from tinygrad.ops import Device
|
||||
Device.DEFAULT = "CLANG"
|
||||
|
||||
# first, 2+3 as a Tensor, the highest level
|
||||
from tinygrad.tensor import Tensor
|
||||
a = Tensor([2])
|
||||
b = Tensor([3])
|
||||
result = a + b
|
||||
print(f"{a.numpy()} + {b.numpy()} = {result.numpy()}")
|
||||
assert result.numpy()[0] == 5.
|
||||
|
||||
# %%
|
||||
# == Tensor (in tinygrad/tensor.py, code 8/10) ==
|
||||
# it's worth reading tinygrad/tensor.py. it's pretty beautiful
|
||||
import tinygrad.mlops as mlops
|
||||
|
||||
# this is the good old familiar Tensor class
|
||||
class Tensor:
|
||||
# these two are pretty straightforward
|
||||
grad: Optional[Tensor]
|
||||
requires_grad: Optional[bool]
|
||||
|
||||
# this is the graph for the autograd engine
|
||||
_ctx: Optional[Function]
|
||||
|
||||
# this is where the data (and other tensor properties) actually live
|
||||
lazydata: LazyBuffer
|
||||
|
||||
# high level ops (hlops) are defined on this class. example: relu
|
||||
def relu(self): return self.maximum(0)
|
||||
|
||||
# log is an mlop, this is the wrapper function in Tensor
|
||||
def log(self): return mlops.Log.apply(self)
|
||||
|
||||
# all the definitions of the derivatives are subclasses of Function (like mlops.Log)
|
||||
# there's only 18 mlops for derivatives for everything (in tinygrad/mlops.py, code 9/10)
|
||||
# if you read one file, read mlops.py. if you read two files, also read tinygrad/tensor.py
|
||||
# you can differentiate the world using the chain rule
|
||||
class Function:
|
||||
# example types of forward and backward
|
||||
def forward(self, x:LazyBuffer) -> LazyBuffer: pass
|
||||
def backward(self, x:LazyBuffer) -> LazyBuffer: pass
|
||||
|
||||
# %%
|
||||
# == LazyBuffer (in tinygrad/lazy.py, code 5/10) ==
|
||||
from tinygrad.helpers import DType
|
||||
|
||||
# this is where the properties live that you thought were a part of Tensor
|
||||
# LazyBuffer is like a Tensor without derivatives, at the mlop layer
|
||||
class LazyBuffer:
|
||||
# these three define the "type" of the buffer, and they are returned as Tensor properties
|
||||
device: str
|
||||
shape: Tuple[int, ...]
|
||||
dtype: DType
|
||||
|
||||
# a ShapeTracker is used to track things like reshapes and permutes
|
||||
# all MovementOps are zero copy in tinygrad!
|
||||
# the ShapeTracker specifies how the data in the RawBuffer matches to the shape
|
||||
# we'll come back to this later
|
||||
st: ShapeTracker
|
||||
|
||||
# if the LazyBuffer is realized, it has a RawBuffer
|
||||
# we will come back to RawBuffers later
|
||||
realized: Optional[RawBuffer]
|
||||
|
||||
# if the lazybuffer is unrealized, it has a LazyOp
|
||||
# this LazyOp describes the computation needed to realize this LazyBuffer
|
||||
op: Optional[LazyOp]
|
||||
|
||||
# LazyOp (in tinygrad/ops.py, code 4/10)
|
||||
# in a tree they form an Abstract Syntax Tree for a single GPU kernel
|
||||
class LazyOp:
|
||||
op: Op # the type of the compute
|
||||
src: Tuple[Union[LazyOp, LazyBuffer], ...] # the sources
|
||||
arg: Optional[Any] = None # and an optional static argument
|
||||
|
||||
# there's currently 28 Ops you have to implement for an accelerator.
|
||||
class UnaryOps(Enum): NOOP = auto(); EXP2 = auto(); LOG2 = auto(); CAST = auto(); SIN = auto(); SQRT = auto()
|
||||
class BinaryOps(Enum): ADD = auto(); SUB = auto(); MUL = auto(); DIV = auto(); CMPLT = auto(); MAX = auto()
|
||||
class ReduceOps(Enum): SUM = auto(); MAX = auto()
|
||||
class MovementOps(Enum): RESHAPE = auto(); PERMUTE = auto(); EXPAND = auto(); PAD = auto(); SHRINK = auto(); STRIDE = auto()
|
||||
class TernaryOps(Enum): MULACC = auto(); WHERE = auto()
|
||||
class LoadOps(Enum): EMPTY = auto(); RAND = auto(); CONST = auto(); FROM = auto(); CONTIGUOUS = auto(); CUSTOM = auto()
|
||||
# NOTE: if you have a CompiledBuffer(DeviceBuffer)
|
||||
# you do not need to implement the MovementOps
|
||||
# as they are handled by the ShapeTracker(in tinygrad/shape/shapetracker.py, code 7/10)
|
||||
Op = Union[UnaryOps, BinaryOps, ReduceOps, MovementOps, TernaryOps, LoadOps]
|
||||
|
||||
# most of tinygrad/lazy.py is concerned with fusing Ops into LazyOps ASTs that map to GPUKernels
|
||||
# it's beyond the scope of this tutorial, but you can read the file if interested
|
||||
|
||||
# %%
|
||||
# == Example: LazyBuffer for 2+3 ==
|
||||
|
||||
from tinygrad.tensor import Tensor
|
||||
from tinygrad.ops import LazyOp, BinaryOps, LoadOps
|
||||
|
||||
# the 2+3 from before
|
||||
result = Tensor([2]) + Tensor([3])
|
||||
print(type(result.lazydata), result.lazydata) # let's look at the lazydata of result
|
||||
|
||||
# you'll see it has a LazyOp
|
||||
# the op type is BinaryOps.ADD
|
||||
# and it has two sources, the 2 and the 3
|
||||
lazyop: LazyOp = result.lazydata.op
|
||||
assert lazyop.op == BinaryOps.ADD
|
||||
assert len(lazyop.src) == 2
|
||||
|
||||
# the first source is the 2, it comes from the CPU
|
||||
# the source is a LazyBuffer that is a "CPU" Tensor
|
||||
# again, a LazyOp AST is like a GPU kernel. you have to copy the data on the device first
|
||||
assert lazyop.src[0].op.op == LoadOps.FROM
|
||||
assert lazyop.src[0].op.src[0].device == "CPU"
|
||||
assert lazyop.src[0].op.src[0].realized._buf[0] == 2, "the src of the FROM LazyOP is a LazyBuffer on the CPU holding [2.]"
|
||||
assert result.lazydata.realized is None, "the LazyBuffer is not realized yet"
|
||||
|
||||
# now we realize the LazyBuffer
|
||||
result.lazydata.realize()
|
||||
assert result.lazydata.realized is not None, "the LazyBuffer is realized!"
|
||||
# this brings us nicely to DeviceBuffer, of which the realized ClangBuffer is a subclass
|
||||
assert 'RawMallocBuffer' in str(type(result.lazydata.realized))
|
||||
# getting ahead of ourselves, but we can copy the DeviceBuffer toCPU
|
||||
assert result.lazydata.realized.toCPU()[0] == 5, "when put in numpy with toCPU, it's 5"
|
||||
|
||||
# %%
|
||||
# == Union[Interpreted, Compiled] (in tinygrad/ops.py, code 5/10) ==
|
||||
|
||||
# Now you have a choice, you can either write a "Interpreted" backend or "Compiled" backend
|
||||
|
||||
# Interpreted backends are very simple (example: CPU and TORCH)
|
||||
class Interpreted:
|
||||
# they have a backing RawBuffer
|
||||
buffer: Type[RawBuffer]
|
||||
|
||||
# and they have a lookup table to functions for the Ops
|
||||
fxn_for_op: Dict[Op, Callable] = {
|
||||
UnaryOps.EXP2: lambda x: np.exp2(x),
|
||||
BinaryOps.ADD: lambda x,y: x+y}
|
||||
|
||||
# Compiled backends take a little more (example: GPU and LLVM)
|
||||
class Compiled:
|
||||
# they also have a backing RawBuffer
|
||||
buffer: Type[RawBuffer]
|
||||
|
||||
# a code generator, which compiles the AST
|
||||
codegen: Type[Linearizer]
|
||||
|
||||
# and a runtime, which runs the generated code
|
||||
runtime: Type[Runtime]
|
||||
|
||||
# Runtime is what actually runs the kernels for a compiled backend
|
||||
class Runtime(ABC):
|
||||
# `name` is the name of the function, and `prg` is the code
|
||||
# the constructor compiles the code
|
||||
def __init__(self, name:str, prg:str): pass
|
||||
# call runs the code on the bufs. NOTE: the output is always bufs[0], but this is just a convention
|
||||
def __call__(self, global_size:Optional[List[int]], local_size:Optional[List[int]], *bufs:List[RawBuffer]): pass
|
||||
|
||||
# %%
|
||||
# == RawBuffer (in tinygrad/runtime/lib.py, code 5/10) ==
|
||||
import numpy as np
|
||||
|
||||
# RawBuffer is where the data is actually held. it's pretty close to just memory
|
||||
class RawBuffer(ABC):
|
||||
# create an empty rawbuffer that holds `size` elements of type `dtype`
|
||||
# `buf` is an opaque container class
|
||||
def __init__(self, size:int, dtype:DType, buf:Any): raise NotImplementedError("must be implemented")
|
||||
|
||||
# fromCPU is classmethod that creates a RawBuffer, it's a classmethod since some runtimes are 0 copy
|
||||
@classmethod
|
||||
def fromCPU(cls:RawBuffer, x:np.ndarray) -> RawBuffer: raise NotImplementedError("must be implemented")
|
||||
|
||||
# toCPU converts the RawBuffer to a numpy array with shape (size,). many backends are 0 copy here
|
||||
def toCPU(self) -> np.ndarray: raise NotImplementedError("must be implemented")
|
||||
|
||||
# RawNumpyBuffer is a RawBuffer example for numpy. It's very simple
|
||||
class RawNumpyBuffer(RawBuffer):
|
||||
# NOTE: the "np.ndarray" is stored in the opaque container
|
||||
def __init__(self, buf:np.ndarray):
|
||||
super().__init__(buf.size, dtypes.from_np(buf.dtype), buf)
|
||||
@classmethod
|
||||
def fromCPU(cls, x): return cls(x)
|
||||
def toCPU(self): return self._buf
|
||||
|
||||
# %%
|
||||
# == Example: 2+3 in raw clang ==
|
||||
|
||||
# RawMallocBuffer is the simplest concrete version of RawBuffer (in tinygrad/ops.py)
|
||||
# it's used for the CLANG and LLVM backends
|
||||
# it's just malloc(size * dtype.itemsize)
|
||||
from tinygrad.runtime.lib import RawMallocBuffer
|
||||
|
||||
# ClangProgram is the simplest runtime (in tinygrad/runtime/ops_clang.py, code 7/10)
|
||||
# __init__ calls clang, and __call__ calls the function in the *.so outputted by clang
|
||||
# in CLANG, global_size and local_size are ignored
|
||||
from tinygrad.runtime.ops_clang import ClangProgram
|
||||
|
||||
# a concrete example looks like this, this adds two size 1 RawBuffer
|
||||
# first we create two numpy buffers containing 2 and 3
|
||||
# then we copy the numpy in to RawMallocBuffers
|
||||
# last, we create an empty output buffer
|
||||
from tinygrad.helpers import dtypes
|
||||
numpy_a, numpy_b = np.array([2], dtype=np.float32), np.array([3], dtype=np.float32)
|
||||
input_a, input_b = RawMallocBuffer.fromCPU(numpy_a), RawMallocBuffer.fromCPU(numpy_b)
|
||||
output = RawMallocBuffer(1, dtypes.float32)
|
||||
|
||||
# compile the program, run it, and 2+3 does indeed equal 5
|
||||
program = ClangProgram("add", f"void add(float *a, float *b, float *c) {{ *a = *b + *c; }}")
|
||||
program(None, None, output, input_a, input_b) # NOTE: the None are for global_size and local_size
|
||||
print(output.toCPU())
|
||||
assert output.toCPU()[0] == 5, "it's still 5"
|
||||
np.testing.assert_allclose(output.toCPU(), numpy_a+numpy_b)
|
||||
|
||||
# %%
|
||||
# == Linearizer (in tinygrad/codegen/linearizer.py, code 4/10) ==
|
||||
|
||||
# in the above example, we wrote the code by hand
|
||||
# normally while using tinygrad you don't do that
|
||||
# the first step of transforming an AST into code is to "linearize" it, think like toposort on the AST
|
||||
# for that, we use the Linearizer, which turns an AST into a list of (linear) UOps
|
||||
|
||||
class UOps(Enum): LOOP = auto(); DEFINE_LOCAL = auto(); LOAD = auto(); ALU = auto(); CONST = auto(); ENDLOOP = auto(); STORE = auto();
|
||||
|
||||
class Token:
|
||||
name: str
|
||||
|
||||
class UOp:
|
||||
uop: UOps
|
||||
out: Optional[Token]
|
||||
vin: List[Token]
|
||||
arg: Any
|
||||
|
||||
class Linearizer:
|
||||
# create the kernel with the AST
|
||||
# NOTE: the AST contains the CompiledBuffers themselves as the root nodes. this will change
|
||||
def __init__(self, ast:LazyOp): pass
|
||||
def process(self): pass
|
||||
def linearize(self): pass
|
||||
|
||||
# when linearize is run, it fills in this list
|
||||
uops: List[UOp]
|
||||
|
||||
from tinygrad.tensor import Tensor
|
||||
from tinygrad.helpers import prod
|
||||
result = Tensor(2).realize() + Tensor(3).realize()
|
||||
result.lazydata.realized = Device[Device.DEFAULT].buffer(prod(result.shape), result.dtype)
|
||||
|
||||
# use the real Linearizer to linearize 2+3
|
||||
from tinygrad.codegen.linearizer import Linearizer, LinearizerOptions
|
||||
linearizer = Linearizer(result.lazydata.op, result.lazydata, LinearizerOptions())
|
||||
linearizer.linearize()
|
||||
|
||||
# print the uops
|
||||
for uop in linearizer.uops: print(uop)
|
||||
|
||||
# output:
|
||||
"""
|
||||
UOps.DEFINE_GLOBAL : [] ('data0', dtypes.float)
|
||||
UOps.LOOP : [] ([], 'global')
|
||||
UOps.LOOP : [] ([], 'local')
|
||||
UOps.LOAD : <acc1_0> [] ConstOp(value=2.0, valid=<1>, invalid_value=0.0)
|
||||
UOps.LOAD : <acc2_0> [] ConstOp(value=3.0, valid=<1>, invalid_value=0.0)
|
||||
UOps.ALU : <alu0> [<acc1_0>, <acc2_0>] BinaryOps.ADD
|
||||
UOps.STORE : [<alu0>] MemOp(name='data0', idx=<0>, local=False, memory_dtype=dtypes.float, valid=<1>, invalid_value=0.0)
|
||||
UOps.ENDLOOP : [] ([], 'global+local')
|
||||
"""
|
||||
|
||||
# %%
|
||||
# == Example: 2+3 autogenerated clang code ==
|
||||
# to generate clang code, the Linearizer is wrapped with CStyleCodegen
|
||||
# here, we have an example where we fetch the generated code from the JIT
|
||||
|
||||
from tinygrad.tensor import Tensor
|
||||
result = Tensor(2) + Tensor(3)
|
||||
|
||||
# we have a global cache used by the JIT
|
||||
# from there, we can see the generated clang code
|
||||
from tinygrad.helpers import GlobalCounters
|
||||
GlobalCounters.cache = [] # enables the cache
|
||||
result.realize() # create the program and runs it
|
||||
cache_saved = GlobalCounters.cache
|
||||
GlobalCounters.cache = None # disable the cache
|
||||
|
||||
# there's one ASTRunner in the cache
|
||||
assert len(cache_saved) == 1
|
||||
prg, bufs, _ = cache_saved[0]
|
||||
|
||||
# print the C Program :)
|
||||
print(prg.prg)
|
||||
|
||||
# after some formatting (the compiler doesn't care)
|
||||
# NOTE: the 2 and 3 are constant folded
|
||||
"""
|
||||
void E_1(float* data0) {
|
||||
for (int idx0 = 0; idx0 < 1; idx0++) {
|
||||
data0[0] = (2.0f) + (3.0f);
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
# %%
|
||||
# == Example: ShapeTracker (in tinygrad/shape/shapetracker.py, code 7/10) ==
|
||||
|
||||
# remember how I said you don't have to write the MovementOps for CompiledBuffers?
|
||||
# that's all thanks to ShapeTracker!
|
||||
# ShapeTracker tracks the indices into the RawBuffer
|
||||
from tinygrad.shape.shapetracker import ShapeTracker
|
||||
|
||||
# create a virtual (10, 10) Tensor. this is just a shape, there's no actual tensor
|
||||
a = ShapeTracker((10, 10))
|
||||
|
||||
# you'll see it has one view. the (10, 1 are the strides)
|
||||
print(a) # ShapeTracker(shape=(10, 10), views=[View((10, 10), (10, 1), 0)])
|
||||
|
||||
# we can permute it, and the strides change
|
||||
a.permute((1,0))
|
||||
print(a) # ShapeTracker(shape=(10, 10), views=[View((10, 10), (1, 10), 0)])
|
||||
|
||||
# we can then reshape it, and the strides change again
|
||||
# note how the permute stays applied
|
||||
a.reshape((5,2,5,2))
|
||||
print(a) # ShapeTracker(shape=(5, 2, 5, 2), views=[View((5, 2, 5, 2), (2, 1, 20, 10), 0)])
|
||||
|
||||
# now, if we were to reshape it to a (100,) shape tensor, we have to create a second view
|
||||
a.reshape((100,))
|
||||
print(a) # ShapeTracker(shape=(100,), views=[
|
||||
# View((5, 2, 5, 2), (2, 1, 20, 10), 0),
|
||||
# View((100,), (1,), 0)])
|
||||
|
||||
# Views stack on top of each other, to allow zero copy for any number of MovementOps
|
||||
# we can render a Python expression for the index at any time
|
||||
idx, _ = a.expr_idxs()
|
||||
print(idx.render()) # (((idx0%10)*10)+(idx0//10))
|
||||
|
||||
# of course, if we reshape it back, the indexes get simple again
|
||||
a.reshape((10,10))
|
||||
idx, _ = a.expr_idxs()
|
||||
print(idx.render()) # ((idx1*10)+idx0)
|
||||
|
||||
# the ShapeTracker still has two views though...
|
||||
print(a) # ShapeTracker(shape=(10, 10), views=[
|
||||
# View((5, 2, 5, 2), (2, 1, 20, 10), 0),
|
||||
# View((10, 10), (10, 1), 0)])
|
||||
|
||||
# ...until we simplify it!
|
||||
a.simplify()
|
||||
print(a) # ShapeTracker(shape=(10, 10), views=[View((10, 10), (1, 10), 0)])
|
||||
|
||||
# and now we permute it back
|
||||
a.permute((1,0))
|
||||
print(a) # ShapeTracker(shape=(10, 10), views=[View((10, 10), (10, 1), 0)])
|
||||
|
||||
# and it's even contiguous
|
||||
assert a.contiguous == True
|
||||
|
||||
# %%
|
||||
# == Example: Variable (in tinygrad/shape/symbolic.py, code 6/10) ==
|
||||
|
||||
# Under the hood, ShapeTracker is powered by a small symbolic algebra library
|
||||
from tinygrad.shape.symbolic import Variable
|
||||
|
||||
# Variable is the basic class from symbolic
|
||||
# it's created with a name and a min and max (inclusive)
|
||||
a = Variable("a", 0, 10)
|
||||
b = Variable("b", 0, 10)
|
||||
|
||||
# some math examples
|
||||
print((a*10).min, (a*10).max) # you'll see a*10 has a min of 0 and max of 100
|
||||
print((a+b).min, (a+b).max) # 0 20, you get the idea
|
||||
|
||||
# but complex expressions are where it gets fun
|
||||
expr = (a + b*10) % 10
|
||||
print(expr.render()) # (a%10)
|
||||
# as you can see, b is gone!
|
||||
|
||||
# one more
|
||||
expr = (a*40 + b) // 20
|
||||
print(expr.render()) # (a*2)
|
||||
print(expr.min, expr.max) # 0 20
|
||||
# this is just "(a*2)"
|
||||
# since b only has a range from 0-10, it can't affect the output
|
||||
|
||||
# %%
|
||||
@@ -1,35 +0,0 @@
|
||||
# Adding a new accelerator to tinygrad
|
||||
|
||||
It's pretty easy to add a new accelerator to tinygrad. All you need to do is implement a total of 27 (optionally 28) low level ops. Then tinygrad takes care of the rest, handling derivatives and syntactic sugar.
|
||||
|
||||
## llops
|
||||
|
||||
These are the ops that you must implement for your accelerator of choice. Compiled Accelerators do not need to implement movement_ops, as they are handled by the ShapeTracker.
|
||||
```
|
||||
Buffer # class of memory on this device
|
||||
unary_op (NOOP, EXP2, LOG2, CAST, SIN, SQRT) # A -> A
|
||||
reduce_op (SUM, MAX) # A -> B (smaller size, B has 1 in shape)
|
||||
binary_op (ADD, SUB, MUL, DIV, CMPEQ, MAX) # A + A -> A (all the same size)
|
||||
movement_op (EXPAND, RESHAPE, PERMUTE, PAD, SHRINK, STRIDE) # A -> B (different size)
|
||||
load_op (EMPTY, RAND, CONST, FROM, CONTIGUOUS, CUSTOM) # -> A (initialize data on device)
|
||||
ternary_op (WHERE) # A, A, A -> A
|
||||
ternary_op [[optional]] (MULACC) # A * A -> B
|
||||
```
|
||||
|
||||
## mlops
|
||||
|
||||
These are the mid level ops that handle the derivatives.
|
||||
```
|
||||
Relu, Log, Exp, Sin # unary ops
|
||||
Sum, Max # reduce ops (with axis argument)
|
||||
Maximum, Add, Sub, Mul, Pow, Div, Equal # binary ops (no broadcasting, use expand)
|
||||
Expand, Reshape, Permute, Pad, Shrink, Flip # movement ops
|
||||
Where # ternary ops
|
||||
```
|
||||
These are implemented in [mlops.py](/tinygrad/mlops.py).
|
||||
|
||||
## hlops
|
||||
|
||||
These are the syntax sugar. They are built on top of the mlops and support most of the things that you could expect from a tensor library.
|
||||
|
||||
These are implemented in [tensor.py](/tinygrad/tensor.py).
|
||||
@@ -1,205 +0,0 @@
|
||||
# List of environment variables that control tinygrad behavior.
|
||||
|
||||
This is a list of environment variable that control the runtime behavior of tinygrad and its examples.
|
||||
Most of these are self-explanatory, and are usually used to set an option at runtime.
|
||||
|
||||
Example: `GPU=1 DEBUG=4 python3 -m pytest`
|
||||
|
||||
However you can also decorate a function to set a value only inside that function.
|
||||
|
||||
```python
|
||||
# in tensor.py (probably only useful if you are a tinygrad developer)
|
||||
@Context(DEBUG=4)
|
||||
def numpy(self) -> ...
|
||||
```
|
||||
|
||||
Or use contextmanager to temporarily set a value inside some scope:
|
||||
|
||||
```python
|
||||
with Context(DEBUG=0):
|
||||
a = Tensor.ones(10, 10)
|
||||
a *= 2
|
||||
```
|
||||
|
||||
## Global Variables
|
||||
The columns of this list are are: Variable, Possible Value(s) and Description.
|
||||
|
||||
- A `#` means that the variable can take any integer value.
|
||||
|
||||
These control the behavior of core tinygrad even when used as a library.
|
||||
|
||||
Variable | Possible Value(s) | Description
|
||||
---|---|---
|
||||
DEBUG | [1-4] | enable debugging output, with 4 you get operations, timings, speed, generated code and more
|
||||
GPU | [1] | enable the GPU backend
|
||||
CUDA | [1] | enable CUDA backend
|
||||
CPU | [1] | enable CPU backend
|
||||
MPS | [1] | enable MPS device (for Mac M1 and after)
|
||||
METAL | [1] | enable Metal backend (for Mac M1 and after)
|
||||
METAL_XCODE | [1] | enable Metal using macOS Xcode SDK
|
||||
TORCH | [1] | enable PyTorch backend
|
||||
CLANG | [1] | enable Clang backend
|
||||
LLVM | [1] | enable LLVM backend
|
||||
LLVMOPT | [1] | enable slightly more expensive LLVM optimizations
|
||||
LAZY | [1] | enable lazy operations (this is the default)
|
||||
OPT | [1-3] | optimization level
|
||||
KOPT | [1-2] | kernel optimization, 1 turns it on, 2 caches the found optimizations
|
||||
GRAPH | [1] | create a graph of all operations (requires graphviz)
|
||||
GRAPHPATH | [/path/to] | where to put the generated graph
|
||||
PRUNEGRAPH | [1] | prune MovementOps and LoadOps from the graph
|
||||
PRINT_PRG | [1] | print program code
|
||||
IMAGE | [1] | enable 2d specific optimizations
|
||||
FLOAT16 | [1] | use float16 for images instead of float32
|
||||
ENABLE_METHOD_CACHE | [1] | enable method cache (this is the default)
|
||||
DISALLOW_ASSIGN | [1] | disallow assignment of tensors
|
||||
CL_EXCLUDE | [name0,name1] | comma-separated list of device names to exclude when using OpenCL GPU backend (like `CL_EXCLUDE=gfx1036`)
|
||||
CL_PLATFORM | [# >= 0] | index of the OpenCL [platform](https://documen.tician.de/pyopencl/runtime_platform.html#pyopencl.Platform) to run on. Defaults to 0.
|
||||
RDNA | [1] | enable the specialized [RDNA 3](https://en.wikipedia.org/wiki/RDNA_3) assembler for AMD 7000-series GPUs. If not set, defaults to generic OpenCL codegen backend.
|
||||
PTX | [1] | enable the specialized [PTX](https://docs.nvidia.com/cuda/parallel-thread-execution/) assembler for Nvidia GPUs. If not set, defaults to generic CUDA codegen backend.
|
||||
|
||||
## File Specific Variables
|
||||
|
||||
These are variables that control the behavior of a specific file, these usually don't affect the library itself.
|
||||
Most of the time these will never be used, but they are here for completeness.
|
||||
|
||||
### accel/ane/2_compile/hwx_parse.py
|
||||
|
||||
Variable | Possible Value(s) | Description
|
||||
---|---|---
|
||||
PRINTALL | [1] | print all ANE registers
|
||||
|
||||
### extra/onnx.py
|
||||
|
||||
Variable | Possible Value(s) | Description
|
||||
---|---|---
|
||||
ONNXLIMIT | [#] | set a limit for ONNX
|
||||
DEBUGONNX | [1] | enable ONNX debugging
|
||||
|
||||
### extra/thneed.py
|
||||
|
||||
Variable | Possible Value(s) | Description
|
||||
---|---|---
|
||||
DEBUGCL | [1-4] | enable Debugging for OpenCL
|
||||
PRINT_KERNEL | [1] | Print OpenCL Kernels
|
||||
|
||||
### extra/kernel_search.py
|
||||
|
||||
Variable | Possible Value(s) | Description
|
||||
---|---|---
|
||||
OP | [1-3] | different operations
|
||||
NOTEST | [1] | enable not testing AST
|
||||
DUMP | [1] | enable dumping of intervention cache
|
||||
REDUCE | [1] | enable reduce operations
|
||||
SIMPLE_REDUCE | [1] | enable simpler reduce operations
|
||||
BC | [1] | enable big conv operations
|
||||
CONVW | [1] | enable convw operations
|
||||
FASTCONV | [1] | enable faster conv operations
|
||||
GEMM | [1] | enable general matrix multiply operations
|
||||
BROKEN | [1] | enable a kind of operation
|
||||
BROKEN3 | [1] | enable a kind of operation
|
||||
|
||||
### examples/vit.py
|
||||
|
||||
Variable | Possible Value(s) | Description
|
||||
---|---|---
|
||||
LARGE | [1] | enable larger dimension model
|
||||
|
||||
### examples/llama.py
|
||||
|
||||
Variable | Possible Value(s) | Description
|
||||
---|---|---
|
||||
WEIGHTS | [1] | enable loading weights
|
||||
|
||||
### examples/mlperf
|
||||
|
||||
Variable | Possible Value(s) | Description
|
||||
---|---|---
|
||||
MODEL | [resnet,retinanet,unet3d,rnnt,bert,maskrcnn] | what models to use
|
||||
|
||||
### examples/benchmark_train_efficientnet.py
|
||||
|
||||
Variable | Possible Value(s) | Description
|
||||
---|---|---
|
||||
CNT | [10] | the amount of times to loop the benchmark
|
||||
BACKWARD | [1] | enable backward pass
|
||||
TRAINING | [1] | set Tensor.training
|
||||
CLCACHE | [1] | enable cache for OpenCL
|
||||
|
||||
### examples/hlb_cifar10.py
|
||||
|
||||
Variable | Possible Value(s) | Description
|
||||
---|---|---
|
||||
TORCHWEIGHTS | [1] | use torch to initialize weights
|
||||
DISABLE_BACKWARD | [1] | don't do backward pass
|
||||
DIST | [1] | enable distributed training
|
||||
STEPS | [#] | number of steps
|
||||
|
||||
### examples/benchmark_train_efficientnet.py & examples/hlb_cifar10.py
|
||||
|
||||
Variable | Possible Value(s) | Description
|
||||
---|---|---
|
||||
ADAM | [1] | use the Adam optimizer
|
||||
|
||||
### examples/train_efficientnet.py
|
||||
|
||||
Variable | Possible Value(s) | Description
|
||||
---|---|---
|
||||
STEPS | [# % 1024] | number of steps
|
||||
TINY | [1] | use a tiny convolution network
|
||||
IMAGENET | [1] | use imagenet for training
|
||||
|
||||
### examples/train_efficientnet.py & examples/train_resnet.py
|
||||
|
||||
Variable | Possible Value(s) | Description
|
||||
---|---|---
|
||||
TRANSFER | [1] | enable to use pretrained data
|
||||
|
||||
### examples & test/external/external_test_opt.py
|
||||
|
||||
Variable | Possible Value(s) | Description
|
||||
---|---|---
|
||||
NUM | [18, 2] | what ResNet[18] / EfficientNet[2] to train
|
||||
|
||||
### test/test_ops.py
|
||||
|
||||
Variable | Possible Value(s) | Description
|
||||
---|---|---
|
||||
PRINT_TENSORS | [1] | print tensors
|
||||
FORWARD_ONLY | [1] | use forward operations only
|
||||
|
||||
### test/test_speed_v_torch.py
|
||||
|
||||
Variable | Possible Value(s) | Description
|
||||
---|---|---
|
||||
TORCHCUDA | [1] | enable the torch cuda backend
|
||||
|
||||
### test/external/external_test_gpu_ast.py
|
||||
|
||||
Variable | Possible Value(s) | Description
|
||||
---|---|---
|
||||
KOPT | [1] | enable kernel optimization
|
||||
KCACHE | [1] | enable kernel cache
|
||||
|
||||
### test/external/external_test_opt.py
|
||||
|
||||
Variable | Possible Value(s) | Description
|
||||
---|---|---
|
||||
ENET_NUM | [-2,-1] | what EfficientNet to use
|
||||
|
||||
### test/test_dtype.py & test/extra/test_utils.py & extra/training.py
|
||||
|
||||
Variable | Possible Value(s) | Description
|
||||
---|---|---
|
||||
CI | [1] | disables some tests for CI
|
||||
|
||||
### examples & extra & test
|
||||
|
||||
Variable | Possible Value(s) | Description
|
||||
---|---|---
|
||||
BS | [8, 16, 32, 64, 128] | batch size to use
|
||||
|
||||
### extra/datasets/imagenet_download.py
|
||||
|
||||
Variable | Possible Value(s) | Description
|
||||
---|---|---
|
||||
IMGNET_TRAIN | [1] | download also training data with imagenet
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 32 KiB |
@@ -1,318 +0,0 @@
|
||||
# tinygrad Quick Start Guide
|
||||
|
||||
This guide assumes no prior knowledge of pytorch or any other deep learning framework, but does assume some basic knowledge of neural networks.
|
||||
It is intended to be a very quick overview of the high level API that tinygrad provides.
|
||||
|
||||
This guide is also structured as a tutorial which at the end of it you will have a working model that can classify handwritten digits.
|
||||
|
||||
We need some imports to get started:
|
||||
|
||||
```python
|
||||
import numpy as np
|
||||
from tinygrad.helpers import Timing
|
||||
```
|
||||
|
||||
## Tensors
|
||||
|
||||
Tensors are the base data structure in tinygrad. They can be thought of as a multidimensional array of a specific data type.
|
||||
All high level operations in tinygrad operate on these tensors.
|
||||
|
||||
The tensor class can be imported like so:
|
||||
|
||||
```python
|
||||
from tinygrad.tensor import Tensor
|
||||
```
|
||||
|
||||
Tensors can be created from an existing data structure like a python list or numpy ndarray:
|
||||
|
||||
```python
|
||||
t1 = Tensor([1, 2, 3, 4, 5])
|
||||
na = np.array([1, 2, 3, 4, 5])
|
||||
t2 = Tensor(na)
|
||||
```
|
||||
|
||||
Tensors can also be created using one of the many factory methods:
|
||||
|
||||
```python
|
||||
full = Tensor.full(shape=(2, 3), fill_value=5) # create a tensor of shape (2, 3) filled with 5
|
||||
zeros = Tensor.zeros(2, 3) # create a tensor of shape (2, 3) filled with 0
|
||||
ones = Tensor.ones(2, 3) # create a tensor of shape (2, 3) filled with 1
|
||||
|
||||
full_like = Tensor.full_like(full, fill_value=2) # create a tensor of the same shape as `full` filled with 2
|
||||
zeros_like = Tensor.zeros_like(full) # create a tensor of the same shape as `full` filled with 0
|
||||
ones_like = Tensor.ones_like(full) # create a tensor of the same shape as `full` filled with 1
|
||||
|
||||
eye = Tensor.eye(3) # create a 3x3 identity matrix
|
||||
arange = Tensor.arange(start=0, stop=10, step=1) # create a tensor of shape (10,) filled with values from 0 to 9
|
||||
|
||||
rand = Tensor.rand(2, 3) # create a tensor of shape (2, 3) filled with random values from a uniform distribution
|
||||
randn = Tensor.randn(2, 3) # create a tensor of shape (2, 3) filled with random values from a normal distribution
|
||||
uniform = Tensor.uniform(2, 3, low=0, high=10) # create a tensor of shape (2, 3) filled with random values from a uniform distribution between 0 and 10
|
||||
```
|
||||
|
||||
There are even more of these factory methods, you can find them in the [tensor.py](/tinygrad/tensor.py) file.
|
||||
|
||||
All the tensors creation methods can take a `dtype` argument to specify the data type of the tensor.
|
||||
|
||||
```python
|
||||
from tinygrad.helpers import dtypes
|
||||
|
||||
t3 = Tensor([1, 2, 3, 4, 5], dtype=dtypes.int32)
|
||||
```
|
||||
|
||||
Tensors allow you to perform operations on them like so:
|
||||
|
||||
```python
|
||||
t4 = Tensor([1, 2, 3, 4, 5])
|
||||
t5 = (t4 + 1) * 2
|
||||
t6 = (t5 * t4).relu().log_softmax()
|
||||
```
|
||||
|
||||
All of these operations are lazy and are only executed when you realize the tensor using `.realize()` or `.numpy()`.
|
||||
|
||||
```python
|
||||
print(t6.numpy())
|
||||
# [-56. -48. -36. -20. 0.]
|
||||
```
|
||||
|
||||
There are a lot more operations that can be performed on tensors, you can find them in the [tensor.py](/tinygrad/tensor.py) file.
|
||||
Additionally reading through [abstractions.py](/docs/abstractions.py) will help you understand how operations on these tensors make their way down to your hardware.
|
||||
|
||||
## Models
|
||||
|
||||
Neural networks in tinygrad are really just represented by the operations performed on tensors.
|
||||
These operations are commonly grouped into the `__call__` method of a class which allows modularization and reuse of these groups of operations.
|
||||
These classes do not need to inherit from any base class, in fact if they don't need any trainable parameters they don't even need to be a class!
|
||||
|
||||
An example of this would be the `nn.Linear` class which represents a linear layer in a neural network.
|
||||
|
||||
```python
|
||||
# from tinygrad.nn import Linear
|
||||
class Linear:
|
||||
def __init__(self, in_features, out_features, bias=True, initialization: str='kaiming_uniform'):
|
||||
self.weight = getattr(Tensor, initialization)(out_features, in_features)
|
||||
self.bias = Tensor.zeros(out_features) if bias else None
|
||||
|
||||
def __call__(self, x):
|
||||
return x.linear(self.weight.transpose(), self.bias)
|
||||
```
|
||||
|
||||
There are more neural network modules already implemented in [nn](/tinygrad/nn/__init__.py), and you can also implement your own.
|
||||
|
||||
We will be implementing a simple neural network that can classify handwritten digits from the MNIST dataset.
|
||||
Our classifier will be a simple 2 layer neural network with a Leaky ReLU activation function.
|
||||
It will use a hidden layer size of 128 and an output layer size of 10 (one for each digit) with no bias on either Linear layer.
|
||||
|
||||
```python
|
||||
from tinygrad.nn import Linear
|
||||
|
||||
class TinyNet:
|
||||
def __init__(self):
|
||||
self.l1 = Linear(784, 128, bias=False)
|
||||
self.l2 = Linear(128, 10, bias=False)
|
||||
|
||||
def __call__(self, x):
|
||||
x = self.l1(x)
|
||||
x = x.leakyrelu()
|
||||
x = self.l2(x)
|
||||
return x
|
||||
|
||||
net = TinyNet()
|
||||
```
|
||||
|
||||
We can see that the forward pass of our neural network is just the sequence of operations performed on the input tensor `x`.
|
||||
We can also see that functional operations like `leakyrelu` are not defined as classes and instead are just methods we can just call.
|
||||
Finally, we just initialize an instance of our neural network, and we are ready to start training it.
|
||||
|
||||
## Training
|
||||
|
||||
Now that we have our neural network defined we can start training it.
|
||||
Training neural networks in tinygrad is super simple.
|
||||
All we need to do is define our neural network, define our loss function, and then call `.backward()` on the loss function to compute the gradients.
|
||||
They can then be used to update the parameters of our neural network using one of the many optimizers in [optim.py](/tinygrad/nn/optim.py).
|
||||
|
||||
First we need to set the training flag in `Tensor`:
|
||||
|
||||
```python
|
||||
Tensor.training = True
|
||||
```
|
||||
|
||||
For our loss function we will be using sparse categorical cross entropy loss.
|
||||
|
||||
```python
|
||||
# from tinygrad.tensor import sparse_categorical_crossentropy
|
||||
def sparse_categorical_crossentropy(self, Y, ignore_index=-1) -> Tensor:
|
||||
loss_mask = Y != ignore_index
|
||||
y_counter = Tensor.arange(self.shape[-1], dtype=dtypes.int32, requires_grad=False, device=self.device).unsqueeze(0).expand(Y.numel(), self.shape[-1])
|
||||
y = ((y_counter == Y.flatten().reshape(-1, 1)).where(-1.0, 0) * loss_mask.reshape(-1, 1)).reshape(*Y.shape, self.shape[-1])
|
||||
return self.log_softmax().mul(y).sum() / loss_mask.sum()
|
||||
```
|
||||
|
||||
As we can see in this implementation of cross entropy loss, there are certain operations that tinygrad does not support.
|
||||
Namely, operations that are load/store or assigning a value to a tensor at a certain index.
|
||||
Load/store ops are not supported in tinygrad because they add complexity when trying to port to different backends and 90% of the models out there don't use/need them.
|
||||
|
||||
For our optimizer we will be using the traditional stochastic gradient descent optimizer with a learning rate of 3e-4.
|
||||
|
||||
```python
|
||||
from tinygrad.nn.optim import SGD
|
||||
|
||||
opt = SGD([net.l1.weight, net.l2.weight], lr=3e-4)
|
||||
```
|
||||
|
||||
We can see that we are passing in the parameters of our neural network to the optimizer.
|
||||
This is due to the fact that the optimizer needs to know which parameters to update.
|
||||
There is a simpler way to do this just by using `get_parameters(net)` from `tinygrad.nn.state` which will return a list of all the parameters in the neural network.
|
||||
The parameters are just listed out explicitly here for clarity.
|
||||
|
||||
Now that we have our network, loss function, and optimizer defined all we are missing is the data to train on!
|
||||
There are a couple of dataset loaders in tinygrad located in [/extra/datasets](/extra/datasets).
|
||||
We will be using the MNIST dataset loader.
|
||||
|
||||
```python
|
||||
from extra.datasets import fetch_mnist
|
||||
```
|
||||
|
||||
Now we have everything we need to start training our neural network.
|
||||
We will be training for 1000 steps with a batch size of 64.
|
||||
|
||||
```python
|
||||
X_train, Y_train, X_test, Y_test = fetch_mnist()
|
||||
|
||||
for step in range(1000):
|
||||
# random sample a batch
|
||||
samp = np.random.randint(0, X_train.shape[0], size=(64))
|
||||
batch = Tensor(X_train[samp], requires_grad=False)
|
||||
# get the corresponding labels
|
||||
labels = Tensor(Y_train[samp])
|
||||
|
||||
# forward pass
|
||||
out = net(batch)
|
||||
|
||||
# compute loss
|
||||
loss = sparse_categorical_crossentropy(out, labels)
|
||||
|
||||
# zero gradients
|
||||
opt.zero_grad()
|
||||
|
||||
# backward pass
|
||||
loss.backward()
|
||||
|
||||
# update parameters
|
||||
opt.step()
|
||||
|
||||
# calculate accuracy
|
||||
pred = out.argmax(axis=-1)
|
||||
acc = (pred == labels).mean()
|
||||
|
||||
if step % 100 == 0:
|
||||
print(f"Step {step+1} | Loss: {loss.numpy()} | Accuracy: {acc.numpy()}")
|
||||
```
|
||||
|
||||
## Evaluation
|
||||
|
||||
Now that we have trained our neural network we can evaluate it on the test set.
|
||||
We will be using the same batch size of 64 and will be evaluating for 1000 of those batches.
|
||||
|
||||
```python
|
||||
# set training flag to false
|
||||
Tensor.training = False
|
||||
|
||||
with Timing("Time: "):
|
||||
avg_acc = 0
|
||||
for step in range(1000):
|
||||
# random sample a batch
|
||||
samp = np.random.randint(0, X_test.shape[0], size=(64))
|
||||
batch = Tensor(X_test[samp], requires_grad=False)
|
||||
# get the corresponding labels
|
||||
labels = Y_test[samp]
|
||||
|
||||
# forward pass
|
||||
out = net(batch)
|
||||
|
||||
# calculate accuracy
|
||||
pred = out.argmax(axis=-1).numpy()
|
||||
avg_acc += (pred == labels).mean()
|
||||
print(f"Test Accuracy: {avg_acc / 1000}")
|
||||
```
|
||||
|
||||
## And that's it
|
||||
|
||||
Highly recommend you check out the [examples/](/examples) folder for more examples of using tinygrad.
|
||||
Reading the source code of tinygrad is also a great way to learn how it works.
|
||||
Specifically the tests in [test/](/test) are a great place to see how to use and the semantics of the different operations.
|
||||
There are also a bunch of models implemented in [models/](/models) that you can use as a reference.
|
||||
|
||||
Additionally, feel free to ask questions in the `#learn-tinygrad` channel on the [discord](https://discord.gg/beYbxwxVdx). Don't ask to ask, just ask!
|
||||
|
||||
## Extras
|
||||
|
||||
### JIT
|
||||
|
||||
Additionally, it is possible to speed up the computation of certain neural networks by using the JIT.
|
||||
Currently, this does not support models with varying input sizes and non tinygrad operations.
|
||||
|
||||
To use the JIT we just need to add a function decorator to the forward pass of our neural network and ensure that the input and output are realized tensors.
|
||||
Or in this case we will create a wrapper function and decorate the wrapper function to speed up the evaluation of our neural network.
|
||||
|
||||
```python
|
||||
from tinygrad.jit import TinyJit
|
||||
|
||||
@TinyJit
|
||||
def jit(x):
|
||||
return net(x).realize()
|
||||
|
||||
with Timing("Time: "):
|
||||
avg_acc = 0
|
||||
for step in range(1000):
|
||||
# random sample a batch
|
||||
samp = np.random.randint(0, X_test.shape[0], size=(64))
|
||||
batch = Tensor(X_test[samp], requires_grad=False)
|
||||
# get the corresponding labels
|
||||
labels = Y_test[samp]
|
||||
|
||||
# forward pass with jit
|
||||
out = jit(batch)
|
||||
|
||||
# calculate accuracy
|
||||
pred = out.argmax(axis=-1).numpy()
|
||||
avg_acc += (pred == labels).mean()
|
||||
print(f"Test Accuracy: {avg_acc / 1000}")
|
||||
```
|
||||
|
||||
You will find that the evaluation time is much faster than before and that your accelerator utilization is much higher.
|
||||
|
||||
### Saving and Loading Models
|
||||
|
||||
The standard weight format for tinygrad is [safetensors](https://github.com/huggingface/safetensors). This means that you can load the weights of any model also using safetensors into tinygrad.
|
||||
There are functions in [state.py](/tinygrad/nn/state.py) to save and load models to and from this format.
|
||||
|
||||
```python
|
||||
from tinygrad.nn.state import safe_save, safe_load, get_state_dict, load_state_dict
|
||||
|
||||
# first we need the state dict of our model
|
||||
state_dict = get_state_dict(net)
|
||||
|
||||
# then we can just save it to a file
|
||||
safe_save(state_dict, "model.safetensors")
|
||||
|
||||
# and load it back in
|
||||
state_dict = safe_load("model.safetensors")
|
||||
load_state_dict(net, state_dict)
|
||||
```
|
||||
|
||||
Many of the models in the [models/](/models) folder have a `load_from_pretrained` method that will download and load the weights for you. These usually are pytorch weights meaning that you would need pytorch installed to load them.
|
||||
|
||||
### Environment Variables
|
||||
|
||||
There exist a bunch of environment variables that control the runtime behavior of tinygrad.
|
||||
Some of the commons ones are `DEBUG` and the different backend enablement variables.
|
||||
|
||||
You can find a full list and their descriptions in [env_vars.md](/docs/env_vars.md).
|
||||
|
||||
### Visualizing the Computation Graph
|
||||
|
||||
It is possible to visualize the computation graph of a neural network using [graphviz](https://graphviz.org/).
|
||||
|
||||
This is easily done by running a single pass (forward or backward!) of the neural network with the environment variable `GRAPH` set to `1`.
|
||||
The graph will be saved to `/tmp/net.svg` by default.
|
||||
@@ -1,59 +0,0 @@
|
||||
# tinygrad Showcase
|
||||
|
||||
Despite being a tiny library, tinygrad is capable of doing a lot of things. From state-of-the-art [vision](https://arxiv.org/abs/1905.11946) to state-of-the-art [language](https://arxiv.org/abs/1706.03762) models.
|
||||
|
||||
## Vision
|
||||
|
||||
### EfficientNet
|
||||
|
||||
You can either pass in the URL of a picture to discover what it is:
|
||||
```sh
|
||||
python3 examples/efficientnet.py https://media.istockphoto.com/photos/hen-picture-id831791190
|
||||
```
|
||||
Or, if you have a camera and OpenCV installed, you can detect what is in front of you:
|
||||
```sh
|
||||
python3 examples/efficientnet.py webcam
|
||||
```
|
||||
|
||||
### YOLOv8
|
||||
|
||||
Take a look at [yolov8.py](/examples/yolov8.py).
|
||||
|
||||

|
||||
|
||||
## Audio
|
||||
|
||||
### Whisper
|
||||
|
||||
Take a look at [whisper.py](/examples/whisper.py). You need pyaudio and torchaudio installed.
|
||||
|
||||
```sh
|
||||
SMALL=1 python3 examples/whisper.py
|
||||
```
|
||||
|
||||
## Generative
|
||||
|
||||
### Generative Adversarial Networks
|
||||
|
||||
Take a look at [mnist_gan.py](/examples/mnist_gan.py).
|
||||
|
||||

|
||||
|
||||
### Stable Diffusion
|
||||
|
||||
```sh
|
||||
python3 examples/stable_diffusion.py
|
||||
```
|
||||
|
||||

|
||||
|
||||
*"a horse sized cat eating a bagel"*
|
||||
|
||||
### LLaMA
|
||||
|
||||
You will need to download and put the weights into the `weights/LLaMA` directory, which may need to be created.
|
||||
|
||||
Then you can have a chat with Stacy:
|
||||
```sh
|
||||
python3 examples/llama.py
|
||||
```
|
||||
+4157
File diff suppressed because it is too large
Load Diff
+1763
File diff suppressed because it is too large
Load Diff
@@ -1,67 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
import gc
|
||||
import time
|
||||
from tqdm import trange
|
||||
from models.efficientnet import EfficientNet
|
||||
from tinygrad.nn.state import get_parameters
|
||||
from tinygrad.nn import optim
|
||||
from tinygrad.tensor import Tensor
|
||||
from tinygrad.ops import GlobalCounters
|
||||
from tinygrad.helpers import getenv
|
||||
|
||||
def tensors_allocated():
|
||||
return sum(isinstance(x, Tensor) for x in gc.get_objects())
|
||||
|
||||
NUM = getenv("NUM", 2)
|
||||
BS = getenv("BS", 8)
|
||||
CNT = getenv("CNT", 10)
|
||||
BACKWARD = getenv("BACKWARD", 0)
|
||||
TRAINING = getenv("TRAINING", 1)
|
||||
ADAM = getenv("ADAM", 0)
|
||||
CLCACHE = getenv("CLCACHE", 0)
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(f"NUM:{NUM} BS:{BS} CNT:{CNT}")
|
||||
model = EfficientNet(NUM, classes=1000, has_se=False, track_running_stats=False)
|
||||
parameters = get_parameters(model)
|
||||
for p in parameters: p.realize()
|
||||
if ADAM: optimizer = optim.Adam(parameters, lr=0.001)
|
||||
else: optimizer = optim.SGD(parameters, lr=0.001)
|
||||
|
||||
Tensor.training = TRAINING
|
||||
Tensor.no_grad = not BACKWARD
|
||||
for i in trange(CNT):
|
||||
GlobalCounters.reset()
|
||||
cpy = time.monotonic()
|
||||
x_train = Tensor.randn(BS, 3, 224, 224, requires_grad=False).realize()
|
||||
y_train = Tensor.randn(BS, 1000, requires_grad=False).realize()
|
||||
|
||||
# TODO: replace with TinyJit
|
||||
if i < 3 or not CLCACHE:
|
||||
st = time.monotonic()
|
||||
out = model.forward(x_train)
|
||||
loss = out.log_softmax().mul(y_train).mean()
|
||||
if i == 2 and CLCACHE: GlobalCounters.cache = []
|
||||
if BACKWARD:
|
||||
optimizer.zero_grad()
|
||||
loss.backward()
|
||||
optimizer.step()
|
||||
mt = time.monotonic()
|
||||
loss.realize()
|
||||
for p in parameters:
|
||||
p.realize()
|
||||
et = time.monotonic()
|
||||
else:
|
||||
st = mt = time.monotonic()
|
||||
for prg, args in cl_cache: prg(*args)
|
||||
et = time.monotonic()
|
||||
|
||||
if i == 2 and CLCACHE:
|
||||
cl_cache = GlobalCounters.cache
|
||||
GlobalCounters.cache = None
|
||||
|
||||
mem_used = GlobalCounters.mem_used
|
||||
loss_cpu = loss.detach().numpy()
|
||||
cl = time.monotonic()
|
||||
|
||||
print(f"{(st-cpy)*1000.0:7.2f} ms cpy, {(cl-st)*1000.0:7.2f} ms run, {(mt-st)*1000.0:7.2f} ms build, {(et-mt)*1000.0:7.2f} ms realize, {(cl-et)*1000.0:7.2f} ms CL, {loss_cpu:7.2f} loss, {tensors_allocated():4d} tensors, {mem_used/1e9:.2f} GB used, {GlobalCounters.global_ops*1e-9/(cl-st):9.2f} GFLOPS")
|
||||
@@ -1,67 +0,0 @@
|
||||
from models.efficientnet import EfficientNet
|
||||
from tinygrad.tensor import Tensor
|
||||
from tinygrad.nn.state import safe_save
|
||||
from extra.utils import fetch
|
||||
from extra.export_model import export_model
|
||||
from tinygrad.helpers import getenv
|
||||
import ast, os
|
||||
|
||||
if __name__ == "__main__":
|
||||
model = EfficientNet(0)
|
||||
model.load_from_pretrained()
|
||||
mode = "clang" if getenv("CLANG", "") != "" else "webgpu" if getenv("WEBGPU", "") != "" else ""
|
||||
prg, inp_size, out_size, state = export_model(model, Tensor.randn(1,3,224,224), mode)
|
||||
if getenv("CLANG", "") == "":
|
||||
safe_save(state, os.path.join(os.path.dirname(__file__), "net.safetensors"))
|
||||
ext = "js" if getenv("WEBGPU", "") != "" else "json"
|
||||
with open(os.path.join(os.path.dirname(__file__), f"net.{ext}"), "w") as text_file:
|
||||
text_file.write(prg)
|
||||
else:
|
||||
cprog = [prg]
|
||||
# image library!
|
||||
cprog += ["#define STB_IMAGE_IMPLEMENTATION", fetch("https://raw.githubusercontent.com/nothings/stb/master/stb_image.h").decode('utf-8').replace("half", "_half")]
|
||||
|
||||
# imagenet labels, move to datasets?
|
||||
lbls = fetch("https://gist.githubusercontent.com/yrevar/942d3a0ac09ec9e5eb3a/raw/238f720ff059c1f82f368259d1ca4ffa5dd8f9f5/imagenet1000_clsidx_to_labels.txt")
|
||||
lbls = ast.literal_eval(lbls.decode('utf-8'))
|
||||
lbls = ['"'+lbls[i]+'"' for i in range(1000)]
|
||||
cprog.append(f"char *lbls[] = {{{','.join(lbls)}}};")
|
||||
cprog.append(f"float input[{inp_size}];")
|
||||
cprog.append(f"float outputs[{out_size}];")
|
||||
|
||||
# buffers (empty + weights)
|
||||
cprog.append("""
|
||||
int main(int argc, char* argv[]) {
|
||||
int DEBUG = getenv("DEBUG") != NULL ? atoi(getenv("DEBUG")) : 0;
|
||||
int X=0, Y=0, chan=0;
|
||||
stbi_uc *image = (argc > 1) ? stbi_load(argv[1], &X, &Y, &chan, 3) : stbi_load_from_file(stdin, &X, &Y, &chan, 3);
|
||||
assert(image != NULL);
|
||||
if (DEBUG) printf("loaded image %dx%d channels %d\\n", X, Y, chan);
|
||||
assert(chan == 3);
|
||||
// resize to input[1,3,224,224] and rescale
|
||||
for (int y = 0; y < 224; y++) {
|
||||
for (int x = 0; x < 224; x++) {
|
||||
// get sample position
|
||||
int tx = (x/224.)*X;
|
||||
int ty = (y/224.)*Y;
|
||||
for (int c = 0; c < 3; c++) {
|
||||
input[c*224*224 + y*224 + x] = (image[ty*X*chan + tx*chan + c] / 255.0 - 0.45) / 0.225;
|
||||
}
|
||||
}
|
||||
}
|
||||
net(input, outputs);
|
||||
float best = -INFINITY;
|
||||
int best_idx = -1;
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
if (outputs[i] > best) {
|
||||
best = outputs[i];
|
||||
best_idx = i;
|
||||
}
|
||||
}
|
||||
if (DEBUG) printf("category : %d (%s) with %f\\n", best_idx, lbls[best_idx], best);
|
||||
else printf("%s\\n", lbls[best_idx]);
|
||||
}""")
|
||||
|
||||
# CLANG=1 python3 examples/compile_efficientnet.py | clang -O2 -lm -x c - -o recognize && DEBUG=1 time ./recognize docs/showcase/stable_diffusion_by_tinygrad.jpg
|
||||
# category : 281 (tabby, tabby cat) with 9.452788
|
||||
print('\n'.join(cprog))
|
||||
@@ -1,104 +0,0 @@
|
||||
# An example to compile a small Tensorflow model to extremely portable C code
|
||||
|
||||
import os, sys
|
||||
os.environ["CLANG"] = '1'
|
||||
os.environ["GPU"] = '1'
|
||||
|
||||
import numpy as np
|
||||
import subprocess
|
||||
import tensorflow as tf
|
||||
import tf2onnx
|
||||
from examples.compile_efficientnet import compile_net
|
||||
from extra.onnx import get_run_onnx
|
||||
from tinygrad.tensor import Tensor
|
||||
|
||||
def get_uncompiled_model2(dataset_size=32, output_size=4):
|
||||
inputs = tf.keras.Input(shape=(dataset_size,), name="inputs")
|
||||
x = tf.keras.layers.Dense(16, activation="relu", name="dense_1")(inputs)
|
||||
x = tf.keras.layers.BatchNormalization()(x)
|
||||
x = tf.keras.layers.Dense(32, activation="relu", name="dense_2")(x)
|
||||
outputs = tf.keras.layers.Dense(output_size, activation="sigmoid", name="predictions")(x)
|
||||
model = tf.keras.Model(inputs=inputs, outputs=outputs)
|
||||
return model
|
||||
|
||||
def create_onnx_model(keras_model):
|
||||
input_signature = [tf.TensorSpec([1,32], tf.float32, name='x')]
|
||||
onnx_model, _ = tf2onnx.convert.from_keras(keras_model, input_signature, opset=13)
|
||||
return onnx_model
|
||||
|
||||
def compile_onnx_model(onnx_model):
|
||||
run_onnx = get_run_onnx(onnx_model)
|
||||
|
||||
from tinygrad.jit import TinyJit
|
||||
@TinyJit
|
||||
def run(x): return run_onnx({"x": x}, debug=False)['predictions'].realize()
|
||||
|
||||
the_input = Tensor.randn(1,32)
|
||||
the_output = run(the_input)
|
||||
the_output = run(the_input)
|
||||
|
||||
special_names = {id(the_input.lazydata.realized.cl): "input", id(the_output.lazydata.realized.cl): "outputs"}
|
||||
cprog, statements, bufs, bufs_to_save = compile_net(run, special_names)
|
||||
cprog = ["#include <string.h>", "#include <stdio.h>", "#include <stdlib.h>"] + cprog
|
||||
|
||||
# buffers (all except input)
|
||||
cprog += [f"float {x[0]}[{x[1]}];" for x in bufs.values() if x[0] != "input"]
|
||||
|
||||
# weights
|
||||
cprog.append("void initialize(float *weights) {")
|
||||
weights = bytes()
|
||||
for name,cl in bufs_to_save.items():
|
||||
cprog.append(f"memcpy({name}, weights + {len(weights)//4}, {len(cl)});")
|
||||
weights += bytes(memoryview(cl)[0:len(cl)//4])
|
||||
cprog.append("}")
|
||||
|
||||
# write the weights to disk
|
||||
with open("/tmp/tf_weights", "wb") as f:
|
||||
f.write(weights)
|
||||
|
||||
# the net
|
||||
cprog += ["float *infer(float *input) {"] + statements + ["return outputs;", "}"]
|
||||
|
||||
# test program
|
||||
cprog.append(f"""int main(int argc, char *argv[]) {{
|
||||
// read in the weights from disk
|
||||
FILE *f = fopen("/tmp/tf_weights", "rb");
|
||||
float *weights = (float *)malloc({len(weights)});
|
||||
fread(weights, 1, {len(weights)}, f);
|
||||
fclose(f);
|
||||
|
||||
// init the net
|
||||
initialize(weights);
|
||||
|
||||
// test run
|
||||
float input[32];
|
||||
for (int i = 0; i < 32; i++) scanf("%f", &input[i]);
|
||||
float *outputs = infer(input);
|
||||
printf("%f %f %f %f\\n", outputs[0], outputs[1], outputs[2], outputs[3]);
|
||||
}}""")
|
||||
|
||||
# ready the program
|
||||
prg = '\n'.join(cprog)
|
||||
print(prg)
|
||||
|
||||
# add test weights
|
||||
subprocess.check_output(['clang', '-O2', '-lm', '-fPIC', '-x', 'c', '-', '-o', "/tmp/tf_test"], input=prg.encode('utf-8'))
|
||||
|
||||
tinygrad_output = [x for x in the_output.numpy()[0]]
|
||||
print("tinygrad:", tinygrad_output, file=sys.stderr)
|
||||
|
||||
c_input = ' '.join(["%f" % x for x in the_input[0].numpy()])+"\n"
|
||||
c_output = [float(x) for x in subprocess.check_output(["/tmp/tf_test"], input=c_input.encode('utf-8')).decode('utf-8').strip().split(" ")]
|
||||
print("compiled:", c_output, file=sys.stderr)
|
||||
|
||||
np.testing.assert_allclose(tinygrad_output, c_output, atol=1e-5, rtol=1e-5)
|
||||
return the_input.numpy(), c_output
|
||||
|
||||
if __name__ == "__main__":
|
||||
keras_model = get_uncompiled_model2()
|
||||
onnx_model = create_onnx_model(keras_model)
|
||||
test_input, test_output = compile_onnx_model(onnx_model)
|
||||
tf_output = keras_model(test_input).numpy()[0]
|
||||
print("keras: ", tf_output, file=sys.stderr)
|
||||
np.testing.assert_allclose(tf_output, test_output, atol=1e-5, rtol=1e-5)
|
||||
|
||||
@@ -1,256 +0,0 @@
|
||||
from typing import Optional, Tuple
|
||||
from numpy.typing import NDArray
|
||||
|
||||
from tinygrad.nn.state import get_parameters
|
||||
from tinygrad.tensor import Tensor
|
||||
from tinygrad.nn import optim
|
||||
from tinygrad.helpers import getenv
|
||||
|
||||
import numpy as np
|
||||
import gym
|
||||
|
||||
|
||||
DEVICE = "GPU" if getenv("GPU") else "CPU"
|
||||
|
||||
|
||||
class Actor:
|
||||
def __init__(self, num_actions: int, num_states: int, hidden_size: Tuple[int, int] = (400, 300)):
|
||||
self.l1 = Tensor.glorot_uniform(num_states, hidden_size[0])
|
||||
self.l2 = Tensor.glorot_uniform(hidden_size[0], hidden_size[1])
|
||||
self.mu = Tensor.glorot_uniform(hidden_size[1], num_actions)
|
||||
|
||||
def forward(self, state: Tensor, upper_bound: float) -> Tensor:
|
||||
out = state.dot(self.l1).relu()
|
||||
out = out.dot(self.l2).relu()
|
||||
out = out.dot(self.mu).tanh()
|
||||
output = out * upper_bound
|
||||
|
||||
return output
|
||||
|
||||
|
||||
class Critic:
|
||||
def __init__(self, num_inputs: int, hidden_size: Tuple[int, int] = (400, 300)):
|
||||
self.l1 = Tensor.glorot_uniform(num_inputs, hidden_size[0])
|
||||
self.l2 = Tensor.glorot_uniform(hidden_size[0], hidden_size[1])
|
||||
self.q = Tensor.glorot_uniform(hidden_size[1], 1)
|
||||
|
||||
def forward(self, state: Tensor, action: Tensor) -> Tensor:
|
||||
inputs = state.cat(action, dim=1)
|
||||
out = inputs.dot(self.l1).relu()
|
||||
out = out.dot(self.l2).relu()
|
||||
q = out.dot(self.q)
|
||||
|
||||
return q
|
||||
|
||||
|
||||
class Buffer:
|
||||
def __init__(self, num_actions: int, num_states: int, buffer_capacity: int = 100000, batch_size: int = 64):
|
||||
self.buffer_capacity = buffer_capacity
|
||||
self.batch_size = batch_size
|
||||
|
||||
self.buffer_counter = 0
|
||||
|
||||
self.state_buffer = np.zeros((self.buffer_capacity, num_states), np.float32)
|
||||
self.action_buffer = np.zeros((self.buffer_capacity, num_actions), np.float32)
|
||||
self.reward_buffer = np.zeros((self.buffer_capacity, 1), np.float32)
|
||||
self.next_state_buffer = np.zeros((self.buffer_capacity, num_states), np.float32)
|
||||
self.done_buffer = np.zeros((self.buffer_capacity, 1), np.float32)
|
||||
|
||||
def record(
|
||||
self, observations: Tuple[Tensor, NDArray, float, NDArray, bool]
|
||||
) -> None:
|
||||
index = self.buffer_counter % self.buffer_capacity
|
||||
|
||||
self.state_buffer[index] = observations[0].detach().numpy()
|
||||
self.action_buffer[index] = observations[1]
|
||||
self.reward_buffer[index] = observations[2]
|
||||
self.next_state_buffer[index] = observations[3]
|
||||
self.done_buffer[index] = observations[4]
|
||||
|
||||
self.buffer_counter += 1
|
||||
|
||||
def sample(self) -> Tuple[Tensor, Tensor, Tensor, Tensor, Tensor]:
|
||||
record_range = min(self.buffer_counter, self.buffer_capacity)
|
||||
batch_indices = np.random.choice(record_range, self.batch_size)
|
||||
|
||||
state_batch = Tensor(self.state_buffer[batch_indices], device=DEVICE, requires_grad=False)
|
||||
action_batch = Tensor(self.action_buffer[batch_indices], device=DEVICE, requires_grad=False)
|
||||
reward_batch = Tensor(self.reward_buffer[batch_indices], device=DEVICE, requires_grad=False)
|
||||
next_state_batch = Tensor(self.next_state_buffer[batch_indices], device=DEVICE, requires_grad=False)
|
||||
done_batch = Tensor(self.done_buffer[batch_indices], device=DEVICE, requires_grad=False)
|
||||
|
||||
return state_batch, action_batch, reward_batch, next_state_batch, done_batch
|
||||
|
||||
|
||||
class GaussianActionNoise:
|
||||
def __init__(self, mean: NDArray, std_deviation: NDArray):
|
||||
self.mean = mean
|
||||
self.std_dev = std_deviation
|
||||
|
||||
def __call__(self) -> Tensor:
|
||||
return Tensor(
|
||||
np.random.default_rng()
|
||||
.normal(self.mean, self.std_dev, size=self.mean.shape)
|
||||
.astype(np.float32),
|
||||
device=DEVICE,
|
||||
requires_grad=False,
|
||||
)
|
||||
|
||||
|
||||
class DeepDeterministicPolicyGradient:
|
||||
"""Deep Deterministic Policy Gradient (DDPG).
|
||||
|
||||
https://arxiv.org/pdf/1509.02971.pdf
|
||||
|
||||
Args:
|
||||
env: The environment to learn from.
|
||||
lr_actor: The learning rate of the actor.
|
||||
lr_critic: The learning rate of the critic.
|
||||
gamma: The discount factor.
|
||||
buffer_capacity: The size of the replay buffer.
|
||||
tau: The soft update coefficient.
|
||||
hidden_size: The number of neurons in the hidden layers of the actor and critic networks.
|
||||
batch_size: The minibatch size for each gradient update.
|
||||
noise_stddev: The standard deviation of the exploration noise.
|
||||
|
||||
Note:
|
||||
In contrast to the original paper, actions are already included in the first layer
|
||||
of the Critic and we use a Gaussian distribution instead of an Ornstein Uhlenbeck
|
||||
process for exploration noise.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
env: gym.Env,
|
||||
lr_actor: float = 0.001,
|
||||
lr_critic: float = 0.002,
|
||||
gamma: float = 0.99,
|
||||
buffer_capacity: int = 100000,
|
||||
tau: float = 0.005,
|
||||
hidden_size: Tuple[int, int] = (400, 300),
|
||||
batch_size: int = 64,
|
||||
noise_stddev: float = 0.1,
|
||||
):
|
||||
self.num_states = env.observation_space.shape[0]
|
||||
self.num_actions = env.action_space.shape[0]
|
||||
self.max_action = env.action_space.high.item()
|
||||
self.min_action = env.action_space.low.item()
|
||||
self.gamma = gamma
|
||||
self.tau = tau
|
||||
self.memory = Buffer(
|
||||
self.num_actions, self.num_states, buffer_capacity, batch_size
|
||||
)
|
||||
self.batch_size = batch_size
|
||||
|
||||
self.noise = GaussianActionNoise(
|
||||
mean=np.zeros(self.num_actions),
|
||||
std_deviation=noise_stddev * np.ones(self.num_actions),
|
||||
)
|
||||
|
||||
self.actor = Actor(self.num_actions, self.num_states, hidden_size)
|
||||
self.critic = Critic(self.num_actions + self.num_states, hidden_size)
|
||||
self.target_actor = Actor(self.num_actions, self.num_states, hidden_size)
|
||||
self.target_critic = Critic(self.num_actions + self.num_states, hidden_size)
|
||||
|
||||
actor_params = get_parameters(self.actor)
|
||||
critic_params = get_parameters(self.critic)
|
||||
target_actor_params = get_parameters(self.target_actor)
|
||||
target_critic_params = get_parameters(self.target_critic)
|
||||
|
||||
if DEVICE == "GPU":
|
||||
[x.gpu_() for x in actor_params + critic_params + target_actor_params + target_critic_params]
|
||||
|
||||
self.actor_optimizer = optim.Adam(actor_params, lr_actor)
|
||||
self.critic_optimizer = optim.Adam(critic_params, lr_critic)
|
||||
|
||||
self.update_network_parameters(tau=1.0)
|
||||
|
||||
def update_network_parameters(self, tau: Optional[float] = None) -> None:
|
||||
"""Updates the parameters of the target networks via 'soft updates'."""
|
||||
if tau is None:
|
||||
tau = self.tau
|
||||
|
||||
for param, target_param in zip(
|
||||
get_parameters(self.actor), get_parameters(self.target_actor)
|
||||
):
|
||||
target_param.assign(param.detach() * tau + target_param * (1.0 - tau))
|
||||
|
||||
for param, target_param in zip(
|
||||
get_parameters(self.critic), get_parameters(self.target_critic)
|
||||
):
|
||||
target_param.assign(param.detach() * tau + target_param * (1.0 - tau))
|
||||
|
||||
def choose_action(self, state: Tensor, evaluate: bool = False) -> NDArray:
|
||||
mu = self.actor.forward(state, self.max_action)
|
||||
|
||||
if not evaluate:
|
||||
mu = mu.add(self.noise())
|
||||
|
||||
mu = mu.clip(self.min_action, self.max_action)
|
||||
|
||||
return mu.detach().numpy()
|
||||
|
||||
def learn(self) -> None:
|
||||
"""Performs a learning step by sampling from replay buffer and updating networks."""
|
||||
if self.memory.buffer_counter < self.batch_size:
|
||||
return
|
||||
|
||||
(
|
||||
state_batch,
|
||||
action_batch,
|
||||
reward_batch,
|
||||
next_state_batch,
|
||||
done_batch,
|
||||
) = self.memory.sample()
|
||||
|
||||
target_actions = self.target_actor.forward(next_state_batch, self.max_action)
|
||||
y = reward_batch + self.gamma * self.target_critic.forward(
|
||||
next_state_batch, target_actions.detach()
|
||||
) * (Tensor.ones(*done_batch.shape, device=DEVICE, requires_grad=False) - done_batch)
|
||||
|
||||
self.critic_optimizer.zero_grad()
|
||||
critic_value = self.critic.forward(state_batch, action_batch)
|
||||
critic_loss = y.detach().sub(critic_value).pow(2).mean()
|
||||
critic_loss.backward()
|
||||
self.critic_optimizer.step()
|
||||
|
||||
self.actor_optimizer.zero_grad()
|
||||
actions = self.actor.forward(state_batch, self.max_action)
|
||||
critic_value = self.critic.forward(state_batch, actions)
|
||||
actor_loss = -critic_value.mean()
|
||||
actor_loss.backward()
|
||||
self.actor_optimizer.step()
|
||||
|
||||
self.update_network_parameters()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
env = gym.make("Pendulum-v1")
|
||||
agent = DeepDeterministicPolicyGradient(env)
|
||||
num_episodes = 150
|
||||
|
||||
for episode in range(1, num_episodes+1):
|
||||
cumulative_reward = 0.0
|
||||
prev_state, info = env.reset() # for older gym versions only state is returned, so remove info
|
||||
done = False
|
||||
|
||||
while not done:
|
||||
prev_state = Tensor(prev_state, device=DEVICE, requires_grad=False)
|
||||
action = agent.choose_action(prev_state)
|
||||
|
||||
state, reward, done, _, info = env.step(action) # for older gym versions there is only one bool, so remove _
|
||||
|
||||
cumulative_reward += reward
|
||||
|
||||
agent.memory.record((prev_state, action, reward, state, done))
|
||||
agent.learn()
|
||||
|
||||
if done:
|
||||
break
|
||||
|
||||
prev_state = state
|
||||
|
||||
print(
|
||||
f"Episode {episode}/{num_episodes} - cumulative reward: {cumulative_reward}"
|
||||
)
|
||||
@@ -1,92 +0,0 @@
|
||||
# load weights from
|
||||
# https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/efficientnet-b0-355c32eb.pth
|
||||
# a rough copy of
|
||||
# https://github.com/lukemelas/EfficientNet-PyTorch/blob/master/efficientnet_pytorch/model.py
|
||||
import sys
|
||||
import io
|
||||
import ast
|
||||
import time
|
||||
import cv2
|
||||
import numpy as np
|
||||
from PIL import Image
|
||||
from tinygrad.tensor import Tensor
|
||||
from tinygrad.helpers import getenv
|
||||
from extra.utils import fetch
|
||||
from tinygrad.jit import TinyJit
|
||||
from models.efficientnet import EfficientNet
|
||||
np.set_printoptions(suppress=True)
|
||||
|
||||
# TODO: you should be able to put these in the jitted function
|
||||
bias = Tensor([0.485, 0.456, 0.406])
|
||||
scale = Tensor([0.229, 0.224, 0.225])
|
||||
|
||||
@TinyJit
|
||||
def _infer(model, img):
|
||||
img = img.permute((2,0,1))
|
||||
img = img / 255.0
|
||||
img = img - bias.reshape((1,-1,1,1))
|
||||
img = img / scale.reshape((1,-1,1,1))
|
||||
return model.forward(img).realize()
|
||||
|
||||
def infer(model, img):
|
||||
# preprocess image
|
||||
aspect_ratio = img.size[0] / img.size[1]
|
||||
img = img.resize((int(224*max(aspect_ratio,1.0)), int(224*max(1.0/aspect_ratio,1.0))))
|
||||
|
||||
img = np.array(img)
|
||||
y0,x0=(np.asarray(img.shape)[:2]-224)//2
|
||||
retimg = img = img[y0:y0+224, x0:x0+224]
|
||||
|
||||
# if you want to look at the image
|
||||
"""
|
||||
import matplotlib.pyplot as plt
|
||||
plt.imshow(img)
|
||||
plt.show()
|
||||
"""
|
||||
|
||||
# run the net
|
||||
out = _infer(model, Tensor(img.astype("float32"))).numpy()
|
||||
|
||||
# if you want to look at the outputs
|
||||
"""
|
||||
import matplotlib.pyplot as plt
|
||||
plt.plot(out[0])
|
||||
plt.show()
|
||||
"""
|
||||
return out, retimg
|
||||
|
||||
if __name__ == "__main__":
|
||||
# instantiate my net
|
||||
model = EfficientNet(getenv("NUM", 0))
|
||||
model.load_from_pretrained()
|
||||
|
||||
# category labels
|
||||
lbls = fetch("https://gist.githubusercontent.com/yrevar/942d3a0ac09ec9e5eb3a/raw/238f720ff059c1f82f368259d1ca4ffa5dd8f9f5/imagenet1000_clsidx_to_labels.txt")
|
||||
lbls = ast.literal_eval(lbls.decode('utf-8'))
|
||||
|
||||
# load image and preprocess
|
||||
url = sys.argv[1] if len(sys.argv) >= 2 else "https://raw.githubusercontent.com/tinygrad/tinygrad/master/docs/showcase/stable_diffusion_by_tinygrad.jpg"
|
||||
if url == 'webcam':
|
||||
cap = cv2.VideoCapture(0)
|
||||
cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)
|
||||
while 1:
|
||||
_ = cap.grab() # discard one frame to circumvent capture buffering
|
||||
ret, frame = cap.read()
|
||||
img = Image.fromarray(frame[:, :, [2,1,0]])
|
||||
lt = time.monotonic_ns()
|
||||
out, retimg = infer(model, img)
|
||||
print(f"{(time.monotonic_ns()-lt)*1e-6:7.2f} ms", np.argmax(out), np.max(out), lbls[np.argmax(out)])
|
||||
SCALE = 3
|
||||
simg = cv2.resize(retimg, (224*SCALE, 224*SCALE))
|
||||
retimg = cv2.cvtColor(simg, cv2.COLOR_RGB2BGR)
|
||||
cv2.imshow('capture', retimg)
|
||||
if cv2.waitKey(1) & 0xFF == ord('q'):
|
||||
break
|
||||
cap.release()
|
||||
cv2.destroyAllWindows()
|
||||
else:
|
||||
img = Image.open(io.BytesIO(fetch(url)))
|
||||
st = time.time()
|
||||
out, _ = infer(model, img)
|
||||
print(np.argmax(out), np.max(out), lbls[np.argmax(out)])
|
||||
print(f"did inference in {(time.time()-st):2f}")
|
||||
@@ -1,212 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
# pip3 install tiktoken
|
||||
|
||||
import functools, argparse
|
||||
import numpy as np
|
||||
from tqdm import trange
|
||||
np.set_printoptions(linewidth=200)
|
||||
from typing import Optional, Tuple
|
||||
|
||||
from tinygrad.helpers import Timing, getenv, dtypes, DEBUG
|
||||
from tinygrad.ops import GlobalCounters
|
||||
from tinygrad.ops import Device
|
||||
from tinygrad.tensor import Tensor
|
||||
from tinygrad.nn import Embedding, Linear
|
||||
from tinygrad.jit import TinyJit
|
||||
from tinygrad.shape.symbolic import Variable
|
||||
|
||||
MAX_CONTEXT = 128
|
||||
|
||||
class LayerNorm:
|
||||
def __init__(self, dim, eps=1e-5):
|
||||
self.eps = eps
|
||||
self.weight = Tensor.ones(dim)
|
||||
self.bias = Tensor.zeros(dim)
|
||||
|
||||
def __call__(self, x:Tensor):
|
||||
return (x.layernorm(eps=self.eps)) * self.weight + self.bias
|
||||
|
||||
class Attention:
|
||||
def __init__(self, dim, n_heads, linear=Linear):
|
||||
self.c_attn = linear(dim, 3*dim, bias=True)
|
||||
self.c_proj = linear(dim, dim, bias=True)
|
||||
self.n_heads = n_heads
|
||||
self.dim = dim
|
||||
self.head_dim = dim // n_heads
|
||||
|
||||
def __call__(self, x:Tensor, cache_k:Optional[Tensor], cache_v:Optional[Tensor], start_pos:int, mask:Optional[Tensor]) -> Tensor:
|
||||
xqkv = self.c_attn(x)
|
||||
xq, xk, xv = [xqkv.slice([None, None, (i*self.dim, (i+1)*self.dim)]) for i in range(3)]
|
||||
xq, xk, xv = [x.reshape(x.shape[0], x.shape[1], self.n_heads, self.head_dim) for x in (xq, xk, xv)]
|
||||
|
||||
bsz, seqlen, _, _ = xq.shape
|
||||
# kv caching!
|
||||
if start_pos == 0:
|
||||
keys, values = xk, xv
|
||||
else:
|
||||
assert cache_k, "no cache"
|
||||
#assert start_pos == cache_k.shape[1] and start_pos == cache_v.shape[1], "cache is wrong shape"
|
||||
assert seqlen == xk.shape[1] and seqlen == xv.shape[1], "seqlen is wrong shape?!?"
|
||||
keys, values = cache_k.cat(xk, dim=1), cache_v.cat(xv, dim=1)
|
||||
|
||||
# save the cache
|
||||
cache_k, cache_v = keys.realize(), values.realize()
|
||||
xq, keys, values = xq.transpose(1, 2), keys.transpose(1, 2), values.transpose(1, 2)
|
||||
output = xq.scaled_dot_product_attention(keys, values, mask).transpose(1, 2).reshape(bsz, seqlen, -1)
|
||||
return self.c_proj(output), cache_k, cache_v
|
||||
|
||||
class FeedForward:
|
||||
def __init__(self, dim, hidden_dim, linear=Linear):
|
||||
self.c_fc = linear(dim, hidden_dim, bias=True)
|
||||
self.c_proj = linear(hidden_dim, dim, bias=True)
|
||||
|
||||
def __call__(self, x:Tensor) -> Tensor:
|
||||
return self.c_proj(self.c_fc(x).gelu())
|
||||
|
||||
class TransformerBlock:
|
||||
def __init__(self, dim, n_heads, norm_eps, linear=Linear):
|
||||
self.attn = Attention(dim, n_heads, linear)
|
||||
self.mlp = FeedForward(dim, 4*dim, linear)
|
||||
self.ln_1 = LayerNorm(dim, norm_eps)
|
||||
self.ln_2 = LayerNorm(dim, norm_eps)
|
||||
self.cache_k, self.cache_v = None, None
|
||||
self.jitted = TinyJit(self.inner)
|
||||
|
||||
def inner(self, x:Tensor, cache_k:Optional[Tensor], cache_v:Optional[Tensor], start_pos:int, mask:Optional[Tensor]):
|
||||
output, cache_k, cache_v = self.attn(self.ln_1(x), cache_k, cache_v, start_pos, mask)
|
||||
h = x + output
|
||||
return (h + self.mlp(self.ln_2(h))).realize(), cache_k, cache_v
|
||||
|
||||
def __call__(self, x:Tensor, start_pos:int, mask:Optional[Tensor]):
|
||||
if start_pos > 0 and mask is None and getenv("JIT"):
|
||||
seqlen = x.shape[1]
|
||||
|
||||
pos = Variable("pos", 1, MAX_CONTEXT)
|
||||
self.cache_k = self.cache_k.reshape(self.cache_k.shape[0], pos, self.cache_k.shape[2], self.cache_k.shape[3])
|
||||
self.cache_v = self.cache_v.reshape(self.cache_v.shape[0], pos, self.cache_v.shape[2], self.cache_v.shape[3])
|
||||
|
||||
ret, cache_k, cache_v = self.jitted(x, self.cache_k, self.cache_v, start_pos, mask)
|
||||
|
||||
# save the cache. with symbolic shape, cast it back to int shape so we have int shape in cache
|
||||
self.cache_k = cache_k.reshape(cache_k.shape[0], start_pos+seqlen, cache_k.shape[2], cache_k.shape[3]).realize()
|
||||
self.cache_v = cache_v.reshape(cache_v.shape[0], start_pos+seqlen, cache_v.shape[2], cache_v.shape[3]).realize()
|
||||
|
||||
return ret
|
||||
else:
|
||||
ret, self.cache_k, self.cache_v = self.inner(x, self.cache_k, self.cache_v, start_pos, mask)
|
||||
return ret
|
||||
|
||||
class Transformer:
|
||||
def __init__(self, dim, n_heads, n_layers, norm_eps=1e-5, vocab_size=50257, linear=Linear, max_seq_len=1024):
|
||||
self.wte = Embedding(vocab_size, dim)
|
||||
self.wpe = Embedding(max_seq_len, dim)
|
||||
self.h = [TransformerBlock(dim, n_heads, norm_eps, linear) for _ in range(n_layers)]
|
||||
self.ln_f = LayerNorm(dim, norm_eps)
|
||||
self.lm_head = linear(dim, vocab_size, bias=False)
|
||||
|
||||
self.embed_jitted = TinyJit(self.embed)
|
||||
self.postprocess_jitted = TinyJit(self.postprocess)
|
||||
|
||||
def embed(self, tokens, pos):
|
||||
tok_emb = self.wte(tokens)
|
||||
pos_emb = self.wpe(pos)
|
||||
h = tok_emb + pos_emb
|
||||
return h.realize()
|
||||
|
||||
def postprocess(self, x, temperature:Optional[float]):
|
||||
logits = self.lm_head(self.ln_f(x))
|
||||
if temperature is not None: return (logits[:, -1, :] / (temperature+1e-10)).softmax().flatten().realize()
|
||||
return logits.realize()
|
||||
|
||||
def __call__(self, tokens:Tensor, start_pos:int, temperature:Optional[float]):
|
||||
_bsz, seqlen = tokens.shape
|
||||
if not hasattr(self, 'allpos'): self.allpos = Tensor.arange(0, MAX_CONTEXT).reshape(1, -1).realize()
|
||||
if seqlen == 1 and start_pos > 0 and getenv("JIT"):
|
||||
start_pos_var = Variable("start_pos", 1, MAX_CONTEXT)
|
||||
pos = self.allpos.shrink(((0, self.allpos.shape[0]), (start_pos_var, start_pos_var+seqlen)))
|
||||
pos.lazydata.st.var_vals[start_pos_var] = start_pos
|
||||
h = self.embed_jitted(tokens, pos).sequential([functools.partial(layer, start_pos=start_pos, mask=None) for layer in self.h])
|
||||
return self.postprocess_jitted(h, temperature)
|
||||
else:
|
||||
pos = self.allpos.shrink(((0, self.allpos.shape[0]), (start_pos, start_pos+seqlen)))
|
||||
mask = Tensor.full((1, 1, seqlen, start_pos + seqlen), float("-inf"), dtype=dtypes.float32).triu(start_pos+1).realize()
|
||||
h = self.embed(tokens, pos).sequential([functools.partial(layer, start_pos=start_pos, mask=mask) for layer in self.h])
|
||||
return self.postprocess(h, temperature)
|
||||
|
||||
# **** files and arguments ****
|
||||
|
||||
MODEL_PARAMS = {
|
||||
'gpt2': dict(n_layers=12, n_heads=12, dim=768), # 124M params
|
||||
'gpt2-medium': dict(n_layers=24, n_heads=16, dim=1024), # 350M params
|
||||
'gpt2-large': dict(n_layers=36, n_heads=20, dim=1280), # 774M params
|
||||
'gpt2-xl': dict(n_layers=48, n_heads=25, dim=1600), # 1558M params
|
||||
}
|
||||
|
||||
def get_url(model_size): return f'https://huggingface.co/{model_size}/resolve/main/pytorch_model.bin'
|
||||
|
||||
class GPT2:
|
||||
@staticmethod
|
||||
def build(model_size="gpt2"):
|
||||
import tiktoken
|
||||
from tinygrad.nn.state import torch_load, load_state_dict, get_state_dict
|
||||
from extra.utils import fetch_as_file
|
||||
tokenizer = tiktoken.get_encoding("gpt2")
|
||||
|
||||
params = MODEL_PARAMS[model_size]
|
||||
model = Transformer(**params)
|
||||
weights = torch_load(fetch_as_file(get_url(model_size)))
|
||||
# special treatment for the Conv1D weights we need to transpose
|
||||
transposed = ['attn.c_attn.weight', 'attn.c_proj.weight', 'mlp.c_fc.weight', 'mlp.c_proj.weight']
|
||||
for k in weights.keys():
|
||||
if any(k.endswith(w) for w in transposed):
|
||||
weights[k] = Tensor(weights[k].numpy().T)
|
||||
# lm head and wte are tied
|
||||
weights['lm_head.weight'] = Tensor(weights['wte.weight'].numpy())
|
||||
|
||||
load_state_dict(model, weights)
|
||||
if getenv("FP16"):
|
||||
for v in get_state_dict(model).values(): v.assign(v.cast(dtypes.float16).realize())
|
||||
return GPT2(model, tokenizer)
|
||||
|
||||
def __init__(self, model, tokenizer):
|
||||
self.model = model
|
||||
self.tokenizer = tokenizer
|
||||
|
||||
def greedy_until(self, prompt:str, max_length:int, temperature:float, timing:bool=False):
|
||||
toks = self.tokenizer.encode(prompt, allowed_special={"<|endoftext|>"})
|
||||
start_pos = 0
|
||||
for _ in trange(max_length, disable=(timing==True)):
|
||||
GlobalCounters.reset()
|
||||
if args.timing: print("")
|
||||
st = GlobalCounters.time_sum_s
|
||||
with Timing(f"ran model in ", on_exit=(lambda et: f", {(GlobalCounters.time_sum_s-st)*1e3:.2f} ms on GPU"+
|
||||
f", {GlobalCounters.global_ops*1e-9:.2f} GOPS, {GlobalCounters.global_mem*1e-9:.2f} GB"+
|
||||
f", {GlobalCounters.global_mem*1e-9/(GlobalCounters.time_sum_s-st):.2f} GB/s") if DEBUG else None, enabled=timing):
|
||||
probs = self.model(Tensor([toks[start_pos:]]), start_pos, temperature)
|
||||
with Timing("sync in ", enabled=timing):
|
||||
probs_np = probs.numpy()
|
||||
tok = int(np.random.choice(len(probs_np), p=probs_np))
|
||||
start_pos = len(toks)
|
||||
toks.append(tok)
|
||||
output = self.tokenizer.decode(toks)
|
||||
return output
|
||||
|
||||
# **** main code ****
|
||||
|
||||
if __name__ == "__main__":
|
||||
Tensor.no_grad = True
|
||||
print(f"using {Device.DEFAULT} backend")
|
||||
|
||||
parser = argparse.ArgumentParser(description='Run GPT2 in tinygrad', formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
||||
parser.add_argument('--prompt', type=str, default="What is the answer to life, the universe, and everything?", help="Phrase to start with")
|
||||
parser.add_argument('--count', type=int, default=100, help="Max number of tokens to generate")
|
||||
parser.add_argument('--temperature', type=float, default=0.8, help="Temperature in the softmax")
|
||||
parser.add_argument('--model_size', type=str, default="gpt2-medium", help="Size of model to use [gpt2, gpt2-medium, gpt2-large, gpt2-xl]")
|
||||
parser.add_argument('--timing', action='store_true', help="Print timing per token")
|
||||
args = parser.parse_args()
|
||||
|
||||
print(f"using {args.model_size}")
|
||||
gpt2 = GPT2.build(args.model_size)
|
||||
print('Generating text...')
|
||||
y = gpt2.greedy_until(args.prompt, args.count, args.temperature, timing=args.timing)
|
||||
print(y)
|
||||
@@ -1,371 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
# setup for distributed
|
||||
from extra import dist
|
||||
from tinygrad.helpers import getenv
|
||||
if __name__ == "__main__":
|
||||
if getenv("DIST"):
|
||||
dist.preinit()
|
||||
|
||||
# tinygrad implementation of https://github.com/tysam-code/hlb-CIFAR10/blob/main/main.py
|
||||
# https://myrtle.ai/learn/how-to-train-your-resnet-8-bag-of-tricks/
|
||||
# https://siboehm.com/articles/22/CUDA-MMM
|
||||
import time
|
||||
import random
|
||||
import numpy as np
|
||||
from extra.datasets import fetch_cifar, cifar_mean, cifar_std
|
||||
from tinygrad import nn
|
||||
from tinygrad.nn.state import get_state_dict
|
||||
from tinygrad.nn import optim
|
||||
from tinygrad.ops import Device
|
||||
from tinygrad.tensor import Tensor
|
||||
from tinygrad.ops import GlobalCounters
|
||||
from extra.lr_scheduler import OneCycleLR
|
||||
from tinygrad.jit import TinyJit
|
||||
from extra.dist import collectives
|
||||
|
||||
BS, EVAL_BS, STEPS = getenv("BS", 512), getenv('EVAL_BS', 500), getenv("STEPS", 1000)
|
||||
|
||||
# hyper-parameters were exactly the same as the original repo
|
||||
bias_scaler = 56
|
||||
hyp = {
|
||||
'opt': {
|
||||
'bias_lr': 1.64 * bias_scaler/512,
|
||||
'non_bias_lr': 1.64 / 512,
|
||||
'bias_decay': 1.08 * 6.45e-4 * BS/bias_scaler,
|
||||
'non_bias_decay': 1.08 * 6.45e-4 * BS,
|
||||
'momentum': 0.85,
|
||||
'percent_start': 0.25,
|
||||
'scaling_factor': 1./9,
|
||||
'loss_scale_scaler': 1./512, # (range: ~1/512 - 16+) was 1/128 from original repo w/ FP16
|
||||
},
|
||||
'net': {
|
||||
'kernel_size': 2, # kernel size for the whitening layer
|
||||
'batch_norm_momentum': .5,
|
||||
'cutmix_size': 3,
|
||||
'cutmix_steps': 490, # different from original repo which used epoch > 12.1 - 6 which is roughly 7*98=686 STEPS
|
||||
'pad_amount': 2
|
||||
}
|
||||
}
|
||||
|
||||
def set_seed(seed):
|
||||
Tensor.manual_seed(getenv('SEED', seed)) # Deterministic
|
||||
random.seed(getenv('SEED', seed))
|
||||
|
||||
# ========== Model ==========
|
||||
def whitening(X, kernel_size=hyp['net']['kernel_size']):
|
||||
def _cov(X):
|
||||
X = X/np.sqrt(X.shape[0] - 1)
|
||||
return X.T @ X
|
||||
|
||||
def _patches(data, patch_size=(kernel_size,kernel_size)):
|
||||
h, w = patch_size
|
||||
c = data.shape[1]
|
||||
return np.lib.stride_tricks.sliding_window_view(data, window_shape=(h,w), axis=(2,3)).transpose((0,3,2,1,4,5)).reshape((-1,c,h,w))
|
||||
|
||||
def _eigens(patches):
|
||||
n,c,h,w = patches.shape
|
||||
Σ = _cov(patches.reshape(n, c*h*w))
|
||||
Λ, V = np.linalg.eigh(Σ, UPLO='U')
|
||||
return np.flip(Λ, 0), np.flip(V.T.reshape(c*h*w, c, h, w), 0)
|
||||
|
||||
Λ, V = _eigens(_patches(X.numpy()))
|
||||
|
||||
return Tensor(V/np.sqrt(Λ+1e-2)[:,None,None,None], requires_grad=False)
|
||||
|
||||
class BatchNorm(nn.BatchNorm2d):
|
||||
def __init__(self, num_features):
|
||||
super().__init__(num_features, track_running_stats=False, eps=1e-12, momentum=hyp['net']['batch_norm_momentum'], affine=True)
|
||||
self.weight.requires_grad = False
|
||||
self.bias.requires_grad = True
|
||||
|
||||
class ConvGroup:
|
||||
def __init__(self, channels_in, channels_out):
|
||||
self.conv1 = nn.Conv2d(channels_in, channels_out, kernel_size=3, padding=1, bias=False)
|
||||
self.conv2 = nn.Conv2d(channels_out, channels_out, kernel_size=3, padding=1, bias=False)
|
||||
|
||||
self.norm1 = BatchNorm(channels_out)
|
||||
self.norm2 = BatchNorm(channels_out)
|
||||
|
||||
def __call__(self, x):
|
||||
x = self.conv1(x)
|
||||
x = x.max_pool2d(2)
|
||||
x = self.norm1(x)
|
||||
x = x.gelu()
|
||||
residual = x
|
||||
x = self.conv2(x)
|
||||
x = self.norm2(x)
|
||||
x = x.gelu()
|
||||
|
||||
return x + residual
|
||||
|
||||
class SpeedyResNet:
|
||||
def __init__(self, W):
|
||||
self.whitening = W
|
||||
self.net = [
|
||||
nn.Conv2d(12, 32, kernel_size=1, bias=False),
|
||||
lambda x: x.gelu(),
|
||||
ConvGroup(32, 64),
|
||||
ConvGroup(64, 256),
|
||||
ConvGroup(256, 512),
|
||||
lambda x: x.max((2,3)),
|
||||
nn.Linear(512, 10, bias=False),
|
||||
lambda x: x.mul(hyp['opt']['scaling_factor'])
|
||||
]
|
||||
def __call__(self, x, training=True):
|
||||
# pad to 32x32 because whitening conv creates 31x31 images that are awfully slow to compute with
|
||||
forward = lambda x: x.conv2d(self.whitening).pad2d((1,0,0,1)).sequential(self.net)
|
||||
return forward(x) if training else forward(x)*0.5 + forward(x[..., ::-1])*0.5
|
||||
|
||||
# ========== Loss ==========
|
||||
def cross_entropy(x:Tensor, y:Tensor, reduction:str='mean', label_smoothing:float=0.0) -> Tensor:
|
||||
y = (1 - label_smoothing)*y + label_smoothing / y.shape[1]
|
||||
if reduction=='none': return -x.log_softmax(axis=1).mul(y).sum(axis=1)
|
||||
if reduction=='sum': return -x.log_softmax(axis=1).mul(y).sum(axis=1).sum()
|
||||
return -x.log_softmax(axis=1).mul(y).sum(axis=1).mean()
|
||||
|
||||
# ========== Preprocessing ==========
|
||||
# TODO currently this only works for RGB in format of NxCxHxW and pads the HxW
|
||||
# implemented in recursive fashion but figuring out how to switch indexing dim
|
||||
# during the loop was a bit tricky
|
||||
def pad_reflect(X, size=2) -> Tensor:
|
||||
padding = ((0,0),(0,0),(size,size),(size,size))
|
||||
p = padding[3]
|
||||
s = X.shape[3]
|
||||
|
||||
X_lr = X[...,:,1:1+p[0]].flip(3).pad(((0,0),(0,0),(0,0),(0,s+p[0]))) + X[...,:,-1-p[1]:-1].flip(3).pad(((0,0),(0,0),(0,0),(s+p[1],0)))
|
||||
X = X.pad(((0,0),(0,0),(0,0),p)) + X_lr
|
||||
|
||||
p = padding[2]
|
||||
s = X.shape[2]
|
||||
X_lr = X[...,1:1+p[0],:].flip(2).pad(((0,0),(0,0),(0,s+p[0]),(0,0))) + X[...,-1-p[1]:-1,:].flip(2).pad(((0,0),(0,0),(s+p[1],0),(0,0)))
|
||||
X = X.pad(((0,0),(0,0),p,(0,0))) + X_lr
|
||||
|
||||
return X
|
||||
|
||||
# return a binary mask in the format of BS x C x H x W where H x W contains a random square mask
|
||||
def make_square_mask(shape, mask_size):
|
||||
is_even = int(mask_size % 2 == 0)
|
||||
center_max = shape[-2]-mask_size//2-is_even
|
||||
center_min = mask_size//2-is_even
|
||||
center = Tensor.rand(shape[0])*(center_max-center_min)+center_min
|
||||
|
||||
d_y = Tensor.arange(0, shape[-2]).reshape((1,1,shape[-2],1))
|
||||
d_x = Tensor.arange(0, shape[-1]).reshape((1,1,1,shape[-1]))
|
||||
d_y = d_y - center.reshape((-1,1,1,1))
|
||||
d_x = d_x - center.reshape((-1,1,1,1))
|
||||
d_y =(d_y >= -(mask_size / 2)) * (d_y <= mask_size / 2)
|
||||
d_x =(d_x >= -(mask_size / 2)) * (d_x <= mask_size / 2)
|
||||
mask = d_y * d_x
|
||||
|
||||
return mask
|
||||
|
||||
def random_crop(X, crop_size=32):
|
||||
mask = make_square_mask(X.shape, crop_size)
|
||||
mask = mask.repeat((1,3,1,1))
|
||||
X_cropped = Tensor(X.flatten().numpy()[mask.flatten().numpy().astype(bool)])
|
||||
|
||||
return X_cropped.reshape((-1, 3, crop_size, crop_size))
|
||||
|
||||
def cutmix(X, Y, mask_size=3):
|
||||
# fill the square with randomly selected images from the same batch
|
||||
mask = make_square_mask(X.shape, mask_size)
|
||||
order = list(range(0, X.shape[0]))
|
||||
random.shuffle(order)
|
||||
X_patch = Tensor(X.numpy()[order,...])
|
||||
Y_patch = Tensor(Y.numpy()[order])
|
||||
X_cutmix = Tensor.where(mask, X_patch, X)
|
||||
mix_portion = float(mask_size**2)/(X.shape[-2]*X.shape[-1])
|
||||
Y_cutmix = mix_portion * Y_patch + (1. - mix_portion) * Y
|
||||
return X_cutmix, Y_cutmix
|
||||
|
||||
# the operations that remain inside batch fetcher is the ones that involves random operations
|
||||
def fetch_batches(X_in, Y_in, BS, seed, is_train):
|
||||
step = 0
|
||||
while True:
|
||||
set_seed(seed)
|
||||
X, Y = X_in, Y_in
|
||||
order = list(range(0, X.shape[0]))
|
||||
random.shuffle(order)
|
||||
if is_train:
|
||||
X = random_crop(X, crop_size=32)
|
||||
X = Tensor.where(Tensor.rand(X.shape[0],1,1,1) < 0.5, X[..., ::-1], X) # flip LR
|
||||
if step >= hyp['net']['cutmix_steps']: X, Y = cutmix(X, Y, mask_size=hyp['net']['cutmix_size'])
|
||||
X, Y = X.numpy(), Y.numpy()
|
||||
for i in range(0, X.shape[0], BS):
|
||||
# pad the last batch
|
||||
batch_end = min(i+BS, Y.shape[0])
|
||||
x = Tensor(X[order[batch_end-BS:batch_end],:])
|
||||
y = Tensor(Y[order[batch_end-BS:batch_end]])
|
||||
step += 1
|
||||
yield x, y
|
||||
|
||||
if not is_train: break
|
||||
seed += 1
|
||||
|
||||
transform = [
|
||||
lambda x: x / 255.0,
|
||||
lambda x: (x - Tensor(cifar_mean).repeat((1024,1)).T.reshape(1,-1))/ Tensor(cifar_std).repeat((1024,1)).T.reshape(1,-1),
|
||||
lambda x: x.reshape((-1,3,32,32))
|
||||
]
|
||||
|
||||
def train_cifar(bs=BS, eval_bs=EVAL_BS, steps=STEPS, seed=32):
|
||||
# this import needs to be done here because this is running in a subprocess
|
||||
from extra.dist import OOB
|
||||
set_seed(seed)
|
||||
Tensor.training = True
|
||||
rank, world_size = getenv("RANK"), getenv("WORLD_SIZE", 1)
|
||||
|
||||
X_train, Y_train, X_test, Y_test = fetch_cifar()
|
||||
# load data and label into GPU and convert to dtype accordingly
|
||||
X_train, X_test = X_train.to(device=Device.DEFAULT).float(), X_test.to(device=Device.DEFAULT).float()
|
||||
Y_train, Y_test = Y_train.to(device=Device.DEFAULT).float(), Y_test.to(device=Device.DEFAULT).float()
|
||||
# one-hot encode labels
|
||||
Y_train, Y_test = Tensor.eye(10)[Y_train], Tensor.eye(10)[Y_test]
|
||||
# preprocess data
|
||||
X_train, X_test = X_train.sequential(transform), X_test.sequential(transform)
|
||||
|
||||
# precompute whitening patches
|
||||
W = whitening(X_train)
|
||||
|
||||
# padding is not timed in the original repo since it can be done all at once
|
||||
X_train = pad_reflect(X_train, size=hyp['net']['pad_amount'])
|
||||
|
||||
model = SpeedyResNet(W)
|
||||
|
||||
# parse the training params into bias and non-bias
|
||||
params_dict = get_state_dict(model)
|
||||
params_bias = []
|
||||
params_non_bias = []
|
||||
for params in params_dict:
|
||||
if params_dict[params].requires_grad is not False:
|
||||
if 'bias' in params:
|
||||
params_bias.append(params_dict[params])
|
||||
else:
|
||||
params_non_bias.append(params_dict[params])
|
||||
|
||||
opt_bias = optim.SGD(params_bias, lr=0.01, momentum=hyp['opt']['momentum'], nesterov=True, weight_decay=hyp['opt']['bias_decay'])
|
||||
opt_non_bias = optim.SGD(params_non_bias, lr=0.01, momentum=hyp['opt']['momentum'], nesterov=True, weight_decay=hyp['opt']['non_bias_decay'])
|
||||
|
||||
# NOTE taken from the hlb_CIFAR repository, might need to be tuned
|
||||
initial_div_factor = 1e16
|
||||
final_lr_ratio = 0.02199
|
||||
pct_start = hyp['opt']['percent_start']
|
||||
lr_sched_bias = OneCycleLR(opt_bias, max_lr=hyp['opt']['bias_lr'] ,pct_start=pct_start, div_factor=initial_div_factor, final_div_factor=1./(initial_div_factor*final_lr_ratio), total_steps=STEPS)
|
||||
lr_sched_non_bias = OneCycleLR(opt_non_bias, max_lr=hyp['opt']['non_bias_lr'] ,pct_start=pct_start, div_factor=initial_div_factor, final_div_factor=1./(initial_div_factor*final_lr_ratio), total_steps=STEPS)
|
||||
|
||||
loss_batchsize_scaler = 512/BS
|
||||
@TinyJit
|
||||
def train_step_jitted(model, optimizer, lr_scheduler, X, Y):
|
||||
out = model(X)
|
||||
loss = cross_entropy(out, Y, reduction='none' ,label_smoothing=0.2).mul(hyp['opt']['loss_scale_scaler']*loss_batchsize_scaler).sum().div(hyp['opt']['loss_scale_scaler'])
|
||||
|
||||
if not getenv("DISABLE_BACKWARD"):
|
||||
# index 0 for bias and 1 for non-bias
|
||||
optimizer[0].zero_grad()
|
||||
optimizer[1].zero_grad()
|
||||
loss.backward()
|
||||
|
||||
if getenv("DIST"):
|
||||
# sync gradients across ranks
|
||||
bucket, offset = [], 0
|
||||
for _, v in params_dict.items():
|
||||
if v.grad is not None: bucket.append(v.grad.flatten())
|
||||
grads = collectives.allreduce(Tensor.cat(*bucket), cache_id="grads")
|
||||
for _, v in params_dict.items():
|
||||
if v.grad is not None:
|
||||
v.grad.assign(grads[offset:offset+v.grad.numel()].reshape(*v.grad.shape))
|
||||
offset += v.grad.numel()
|
||||
|
||||
optimizer[0].step()
|
||||
optimizer[1].step()
|
||||
lr_scheduler[0].step()
|
||||
lr_scheduler[1].step()
|
||||
return loss.realize()
|
||||
|
||||
@TinyJit
|
||||
def eval_step_jitted(model, X, Y):
|
||||
out = model(X, training=False)
|
||||
loss = cross_entropy(out, Y, reduction='mean')
|
||||
correct = out.argmax(axis=1) == Y.argmax(axis=1)
|
||||
return correct.realize(), loss.realize()
|
||||
|
||||
# 97 steps in 2 seconds = 20ms / step Tensor.training = True
|
||||
|
||||
# step is 1163.42 GOPS = 56 TFLOPS!!!, 41% of max 136
|
||||
# 4 seconds for tfloat32 ~ 28 TFLOPS, 41% of max 68
|
||||
# 6.4 seconds for float32 ~ 17 TFLOPS, 50% of max 34.1
|
||||
# 4.7 seconds for float32 w/o channels last. 24 TFLOPS. we get 50ms then i'll be happy. only 64x off
|
||||
|
||||
# https://www.anandtech.com/show/16727/nvidia-announces-geforce-rtx-3080-ti-3070-ti-upgraded-cards-coming-in-june
|
||||
# 136 TFLOPS is the theoretical max w float16 on 3080 Ti
|
||||
|
||||
best_eval = -1
|
||||
i = 0
|
||||
batcher = fetch_batches(X_train, Y_train, BS=BS, seed=seed, is_train=True)
|
||||
while i <= STEPS:
|
||||
if i%100 == 0 and i > 1:
|
||||
# Use Tensor.training = False here actually bricks batchnorm, even with track_running_stats=True
|
||||
corrects = []
|
||||
losses = []
|
||||
for Xt, Yt in fetch_batches(X_test, Y_test, BS=EVAL_BS, seed=seed, is_train=False):
|
||||
# further split batch if distributed
|
||||
if getenv("DIST"):
|
||||
Xt, Yt = Xt.chunk(min(world_size, 5), 0)[min(rank, 4)], Yt.chunk(min(world_size, 5), 0)[min(rank, 4)]
|
||||
|
||||
correct, loss = eval_step_jitted(model, Xt, Yt)
|
||||
losses.append(loss.numpy().tolist())
|
||||
corrects.extend(correct.numpy().tolist())
|
||||
|
||||
# collect accuracy across ranks
|
||||
correct_sum, correct_len = sum(corrects), len(corrects)
|
||||
if getenv("DIST"):
|
||||
if rank == 0:
|
||||
for j in range(1, min(world_size, 5)):
|
||||
recv_sum, recv_len = OOB.recv(j)
|
||||
correct_sum += recv_sum
|
||||
correct_len += recv_len
|
||||
elif rank < min(world_size, 5):
|
||||
OOB.send((correct_sum, correct_len), 0)
|
||||
|
||||
# only rank 0 prints
|
||||
if rank == 0:
|
||||
acc = correct_sum/correct_len*100.0
|
||||
if acc > best_eval:
|
||||
best_eval = acc
|
||||
print(f"eval {correct_sum}/{correct_len} {acc:.2f}%, {(sum(losses)/len(losses)):7.2f} val_loss STEP={i}")
|
||||
if STEPS == 0 or i==STEPS: break
|
||||
X, Y = next(batcher)
|
||||
# further split batch if distributed
|
||||
if getenv("DIST"):
|
||||
X, Y = X.chunk(world_size, 0)[rank], Y.chunk(world_size, 0)[rank]
|
||||
GlobalCounters.reset()
|
||||
st = time.monotonic()
|
||||
loss = train_step_jitted(model, [opt_bias, opt_non_bias], [lr_sched_bias, lr_sched_non_bias], X, Y)
|
||||
et = time.monotonic()
|
||||
loss_cpu = loss.numpy()
|
||||
cl = time.monotonic()
|
||||
print(f"{i:3d} {(cl-st)*1000.0:7.2f} ms run, {(et-st)*1000.0:7.2f} ms python, {(cl-et)*1000.0:7.2f} ms CL, {loss_cpu:7.2f} loss, {opt_non_bias.lr.numpy()[0]:.6f} LR, {GlobalCounters.mem_used/1e9:.2f} GB used, {GlobalCounters.global_ops*1e-9/(cl-st):9.2f} GFLOPS")
|
||||
i += 1
|
||||
|
||||
if __name__ == "__main__":
|
||||
if not getenv("DIST"):
|
||||
train_cifar()
|
||||
else: # distributed
|
||||
from tinygrad.runtime.ops_gpu import CL
|
||||
devices = [f"gpu:{i}" for i in range(len(CL.devices))]
|
||||
world_size = len(devices)
|
||||
|
||||
# ensure that the batch size is divisible by the number of devices
|
||||
assert BS % world_size == 0, f"batch size {BS} is not divisible by world size {world_size}"
|
||||
|
||||
# ensure that the evaluation batch size is divisible by the number of devices
|
||||
assert EVAL_BS % min(world_size, 5) == 0, f"evaluation batch size {EVAL_BS} is not divisible by world size {min(world_size, 5)}"
|
||||
|
||||
# init out-of-band communication
|
||||
dist.init_oob(world_size)
|
||||
|
||||
# start the processes
|
||||
processes = []
|
||||
for rank, device in enumerate(devices):
|
||||
processes.append(dist.spawn(rank, device, fn=train_cifar, args=()))
|
||||
for p in processes: p.join()
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user