Compare commits

..
1 Commits
Author SHA1 Message Date
geohot e7cfac01f8 test_mismatch_reduce 2025-08-06 09:49:37 -07:00
177 changed files with 223523 additions and 3837 deletions
+7 -7
View File
@@ -121,7 +121,7 @@ runs:
echo 'Acquire::GzipIndexes "true";' | sudo tee /etc/apt/apt.conf.d/gzip echo 'Acquire::GzipIndexes "true";' | sudo tee /etc/apt/apt.conf.d/gzip
echo 'Acquire::http::Pipeline-Depth "5";' | sudo tee -a /etc/apt/apt.conf.d/99parallel echo 'Acquire::http::Pipeline-Depth "5";' | sudo tee -a /etc/apt/apt.conf.d/99parallel
echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' | sudo tee -a /etc/apt/apt.conf.d/99keep-debs echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' | sudo tee -a /etc/apt/apt.conf.d/99keep-debs
- name: Add OpenCL Repo - name: Add OpenCL Repo
if: inputs.opencl == 'true' && runner.os == 'Linux' if: inputs.opencl == 'true' && runner.os == 'Linux'
shell: bash shell: bash
@@ -174,7 +174,7 @@ runs:
if [[ "${{ inputs.llvm }}" == "true" ]]; then if [[ "${{ inputs.llvm }}" == "true" ]]; then
pkgs+=" libllvm20 clang-20 lld-20" pkgs+=" libllvm20 clang-20 lld-20"
fi fi
echo "pkgs=$pkgs" >> "$GITHUB_OUTPUT" echo "pkgs=$pkgs" >> "$GITHUB_OUTPUT"
echo "hash=$(echo -n "$pkgs" | sha256sum | cut -d' ' -f1)" >> "$GITHUB_OUTPUT" echo "hash=$(echo -n "$pkgs" | sha256sum | cut -d' ' -f1)" >> "$GITHUB_OUTPUT"
@@ -183,21 +183,21 @@ runs:
uses: actions/cache@v4 uses: actions/cache@v4
with: with:
path: /var/cache/apt/archives/ path: /var/cache/apt/archives/
key: ${{ runner.os }}-apt-${{ steps.apt-pkgs.outputs.hash }}-${{ env.APT_CACHE_VERSION }} key: ${{ runner.os }}-apt-${{ steps.apt-pkgs.outputs.hash }}
- name: Run apt Update + Install - name: Run apt Update + Install
if: runner.os == 'Linux' && (inputs.opencl == 'true' || inputs.amd == 'true' || inputs.cuda == 'true' || inputs.webgpu == 'true' || inputs.llvm == 'true') if: runner.os == 'Linux' && (inputs.opencl == 'true' || inputs.amd == 'true' || inputs.cuda == 'true' || inputs.webgpu == 'true' || inputs.llvm == 'true')
shell: bash shell: bash
run: | run: |
sudo apt -qq update || true sudo apt -qq update || true
# ******** do install ******** # ******** do install ********
if [[ -n "${{ steps.apt-pkgs.outputs.pkgs }}" ]]; then if [[ -n "${{ steps.apt-pkgs.outputs.pkgs }}" ]]; then
sudo apt-get -y --allow-unauthenticated --no-install-recommends install ${{ steps.apt-pkgs.outputs.pkgs }} sudo apt-get -y --allow-unauthenticated --no-install-recommends install ${{ steps.apt-pkgs.outputs.pkgs }}
fi fi
sudo chown -R $USER:$USER /var/cache/apt/archives/ sudo chown -R $USER:$USER /var/cache/apt/archives/
# **** AMD **** # **** AMD ****
- name: Setup AMD (Linux) - name: Setup AMD (Linux)
if: inputs.amd == 'true' && runner.os == 'Linux' if: inputs.amd == 'true' && runner.os == 'Linux'
@@ -234,7 +234,7 @@ runs:
cache-name: cache-gpuocelot-build cache-name: cache-gpuocelot-build
with: with:
path: ${{ github.workspace }}/gpuocelot/ocelot path: ${{ github.workspace }}/gpuocelot/ocelot
key: ${{ runner.os }}-gpuocelot-b16039dc940dc6bc4ea0a98380495769ff35ed99-rebuild-${{ env.BUILD_CACHE_VERSION }} key: ${{ runner.os }}-gpuocelot-b16039dc940dc6bc4ea0a98380495769ff35ed99-rebuild-0
- name: Clone/compile gpuocelot - name: Clone/compile gpuocelot
if: inputs.ocelot == 'true' && steps.cache-build.outputs.cache-hit != 'true' if: inputs.ocelot == 'true' && steps.cache-build.outputs.cache-hit != 'true'
shell: bash shell: bash
+23 -22
View File
@@ -62,8 +62,10 @@ jobs:
run: BENCHMARK_LOG=stable_diffusion_xl CAPTURE_PROCESS_REPLAY=0 JIT=1 python3.11 examples/sdxl.py --seed 0 --noshow --timing | tee sdxl.txt run: BENCHMARK_LOG=stable_diffusion_xl CAPTURE_PROCESS_REPLAY=0 JIT=1 python3.11 examples/sdxl.py --seed 0 --noshow --timing | tee sdxl.txt
- name: Run model inference benchmark - name: Run model inference benchmark
run: METAL=1 python3.11 test/external/external_model_benchmark.py run: METAL=1 python3.11 test/external/external_model_benchmark.py
- name: Run huggingface_onnx test
run: METAL=1 python3.11 extra/huggingface_onnx/run_models.py test --debug FacebookAI/xlm-roberta-large
- name: Test speed vs torch - name: Test speed vs torch
run: BIG=2 MPS=1 python3.11 test/speed/external_test_speed_v_torch.py | tee torch_speed.txt run: BIG=2 MPS=1 python3.11 test/test_speed_v_torch.py | tee torch_speed.txt
- name: Test tensor cores - name: Test tensor cores
run: METAL=1 python3.11 test/test_linearizer.py TestLinearizer.test_tensor_cores TestLinearizer.test_tensor_cores_padded TestLinearizer.test_tensor_cores_padded_uops run: METAL=1 python3.11 test/test_linearizer.py TestLinearizer.test_tensor_cores TestLinearizer.test_tensor_cores_padded TestLinearizer.test_tensor_cores_padded_uops
- name: Test AMX tensor cores - name: Test AMX tensor cores
@@ -187,7 +189,7 @@ jobs:
- name: Run model inference benchmark - name: Run model inference benchmark
run: NV=1 CAPTURE_PROCESS_REPLAY=0 NOCLANG=1 python3 test/external/external_model_benchmark.py run: NV=1 CAPTURE_PROCESS_REPLAY=0 NOCLANG=1 python3 test/external/external_model_benchmark.py
- name: Test speed vs torch - name: Test speed vs torch
run: NV=1 CAPTURE_PROCESS_REPLAY=0 HALF=1 BIG=2 TORCHCUDA=1 python3 test/speed/external_test_speed_v_torch.py | tee torch_speed.txt run: NV=1 CAPTURE_PROCESS_REPLAY=0 HALF=1 BIG=2 TORCHCUDA=1 python3 test/test_speed_v_torch.py | tee torch_speed.txt
- name: Test speed vs theoretical - name: Test speed vs theoretical
run: NV=1 IGNORE_BEAM_CACHE=1 BEAM_DEBUG=1 DEBUG=1 python -m pytest -rA test/external/speed_v_theoretical.py --durations=20 run: NV=1 IGNORE_BEAM_CACHE=1 BEAM_DEBUG=1 DEBUG=1 python -m pytest -rA test/external/speed_v_theoretical.py --durations=20
- name: Test benchmark allreduce - name: Test benchmark allreduce
@@ -323,7 +325,7 @@ jobs:
run: BENCHMARK_LOG=resnet_10steps_6gpu NV=1 CAPTURE_PROCESS_REPLAY=0 DEFAULT_FLOAT=HALF BENCHMARK=10 BS=1536 GPUS=6 MODEL=resnet python3 examples/mlperf/model_train.py | tee train_resnet.txt run: BENCHMARK_LOG=resnet_10steps_6gpu NV=1 CAPTURE_PROCESS_REPLAY=0 DEFAULT_FLOAT=HALF BENCHMARK=10 BS=1536 GPUS=6 MODEL=resnet python3 examples/mlperf/model_train.py | tee train_resnet.txt
- name: Run 10 MLPerf Bert training steps (6 gpu) - name: Run 10 MLPerf Bert training steps (6 gpu)
# TODO: remove BERT_LAYERS once scheduler is fast # TODO: remove BERT_LAYERS once scheduler is fast
run: BENCHMARK_LOG=bert_10steps_6gpu NV=1 CAPTURE_PROCESS_REPLAY=0 DEFAULT_FLOAT=HALF BENCHMARK=10 BS=66 GPUS=6 BERT_LAYERS=2 MODEL=bert python3 examples/mlperf/model_train.py | tee train_bert.txt run: BENCHMARK_LOG=bert_10steps_6gpu NV=1 CAPTURE_PROCESS_REPLAY=0 DEFAULT_FLOAT=HALF BENCHMARK=10 BS=66 GPUS=6 BERT_LAYERS=2 FUSE_ARANGE=1 FUSE_ARANGE_UINT=0 MODEL=bert python3 examples/mlperf/model_train.py | tee train_bert.txt
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@v4
with: with:
name: Speed (NVIDIA Training) name: Speed (NVIDIA Training)
@@ -389,7 +391,7 @@ jobs:
#- name: Test speed vs torch #- name: Test speed vs torch
# run: | # run: |
# python3 -c "import torch; print(torch.__version__)" # python3 -c "import torch; print(torch.__version__)"
# LD_PRELOAD="/opt/rocm/lib/libhsa-runtime64.so" HSA=1 BIG=2 TORCHCUDA=1 python3 test/speed/external_test_speed_v_torch.py | tee torch_speed.txt # LD_PRELOAD="/opt/rocm/lib/libhsa-runtime64.so" HSA=1 BIG=2 TORCHCUDA=1 python3 test/test_speed_v_torch.py | tee torch_speed.txt
- name: Test speed vs theoretical - name: Test speed vs theoretical
run: AMD=1 IGNORE_BEAM_CACHE=1 BEAM_DEBUG=1 DEBUG=1 python -m pytest -rA test/external/speed_v_theoretical.py --durations=20 run: AMD=1 IGNORE_BEAM_CACHE=1 BEAM_DEBUG=1 DEBUG=1 python -m pytest -rA test/external/speed_v_theoretical.py --durations=20
- name: Test tensor cores - name: Test tensor cores
@@ -574,7 +576,7 @@ jobs:
run: BENCHMARK_LOG=resnet_10steps_6gpu AMD=1 CAPTURE_PROCESS_REPLAY=0 DEFAULT_FLOAT=HALF BENCHMARK=10 BS=1536 GPUS=6 MODEL=resnet python3 examples/mlperf/model_train.py | tee train_resnet.txt run: BENCHMARK_LOG=resnet_10steps_6gpu AMD=1 CAPTURE_PROCESS_REPLAY=0 DEFAULT_FLOAT=HALF BENCHMARK=10 BS=1536 GPUS=6 MODEL=resnet python3 examples/mlperf/model_train.py | tee train_resnet.txt
- name: Run 10 MLPerf Bert training steps (6 gpu) - name: Run 10 MLPerf Bert training steps (6 gpu)
# TODO: remove BERT_LAYERS once scheduler is fast # TODO: remove BERT_LAYERS once scheduler is fast
run: BENCHMARK_LOG=bert_10steps_6gpu AMD=1 CAPTURE_PROCESS_REPLAY=0 DEFAULT_FLOAT=HALF BENCHMARK=10 BS=66 GPUS=6 BERT_LAYERS=2 MODEL=bert python3 examples/mlperf/model_train.py | tee train_bert.txt run: BENCHMARK_LOG=bert_10steps_6gpu AMD=1 CAPTURE_PROCESS_REPLAY=0 DEFAULT_FLOAT=HALF BENCHMARK=10 BS=66 GPUS=6 BERT_LAYERS=2 FUSE_ARANGE=1 FUSE_ARANGE_UINT=0 MODEL=bert python3 examples/mlperf/model_train.py | tee train_bert.txt
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@v4
with: with:
name: Speed (AMD MLPerf) name: Speed (AMD MLPerf)
@@ -603,18 +605,18 @@ jobs:
rm -f /tmp/staging.db /tmp/staging.db-shm /tmp/staging.db-wal rm -f /tmp/staging.db /tmp/staging.db-shm /tmp/staging.db-wal
- name: reset process replay - name: reset process replay
run: test/external/process_replay/reset.py run: test/external/process_replay/reset.py
- name: benchmark openpilot 0.9.9 driving_vision - name: validate openpilot 0.9.7
run: BENCHMARK_LOG=openpilot_0_9_9_vision PYTHONPATH=. NOLOCALS=1 FLOAT16=1 IMAGE=2 QCOM=1 taskset -c 4-7 python3 test/external/external_benchmark_openpilot.py https://github.com/commaai/openpilot/raw/v0.9.9/selfdrive/modeld/models/driving_vision.onnx run: PYTHONPATH=. FLOAT16=0 IMAGE=2 QCOM=1 taskset -c 4-7 python3 test/external/external_benchmark_openpilot.py https://github.com/commaai/openpilot/raw/v0.9.7/selfdrive/modeld/models/supercombo.onnx | tee openpilot_image_0_9_7.txt
- name: benchmark openpilot 0.9.9 driving_policy - name: benchmark openpilot 0.9.7
run: BENCHMARK_LOG=openpilot_0_9_9_policy PYTHONPATH=. NOLOCALS=1 FLOAT16=1 IMAGE=2 QCOM=1 taskset -c 4-7 python3 test/external/external_benchmark_openpilot.py https://github.com/commaai/openpilot/raw/v0.9.9/selfdrive/modeld/models/driving_policy.onnx run: BENCHMARK_LOG=openpilot_0_9_7 PYTHONPATH=. QCOM=1 taskset -c 4-7 python3 test/external/external_benchmark_openpilot.py https://github.com/commaai/openpilot/raw/v0.9.7/selfdrive/modeld/models/supercombo.onnx | tee openpilot_0_9_7.txt
- name: benchmark openpilot 0.9.9 dmonitoring - name: benchmark openpilot w IMAGE=2 0.9.7
run: BENCHMARK_LOG=openpilot_0_9_9_dmonitoring PYTHONPATH=. NOLOCALS=1 FLOAT16=1 IMAGE=2 QCOM=1 taskset -c 4-7 python3 test/external/external_benchmark_openpilot.py https://github.com/commaai/openpilot/raw/v0.9.9/selfdrive/modeld/models/dmonitoring_model.onnx run: BENCHMARK_LOG=openpilot_0_9_7_image PYTHONPATH=. NOLOCALS=1 FLOAT16=1 IMAGE=2 QCOM=1 taskset -c 4-7 python3 test/external/external_benchmark_openpilot.py https://github.com/commaai/openpilot/raw/v0.9.7/selfdrive/modeld/models/supercombo.onnx | tee openpilot_image_0_9_7.txt
- name: openpilot compile3 0.9.9 driving_vision - name: openpilot compile3 0.9.7
run: PYTHONPATH="." QCOM=1 taskset -c 4-7 python3 examples/openpilot/compile3.py https://github.com/commaai/openpilot/raw/v0.9.9/selfdrive/modeld/models/driving_vision.onnx run: PYTHONPATH="." QCOM=1 taskset -c 4-7 python3 examples/openpilot/compile3.py https://github.com/commaai/openpilot/raw/v0.9.7/selfdrive/modeld/models/supercombo.onnx
- name: openpilot compile3 0.9.9 driving_policy - name: openpilot compile3 0.9.7+ tomb raider
run: PYTHONPATH="." QCOM=1 taskset -c 4-7 python3 examples/openpilot/compile3.py https://github.com/commaai/openpilot/raw/v0.9.9/selfdrive/modeld/models/driving_policy.onnx run: PYTHONPATH="." QCOM=1 taskset -c 4-7 python3 examples/openpilot/compile3.py https://github.com/commaai/openpilot/raw/e8bea2c78ffa92685ece511e9b554122aaf1a79d/selfdrive/modeld/models/supercombo.onnx
- name: openpilot compile3 0.9.9 dmonitoring - name: openpilot dmonitoring compile3 0.9.7
run: PYTHONPATH="." QCOM=1 taskset -c 4-7 python3 examples/openpilot/compile3.py https://github.com/commaai/openpilot/raw/v0.9.9/selfdrive/modeld/models/dmonitoring_model.onnx run: PYTHONPATH="." QCOM=1 taskset -c 4-7 python3 examples/openpilot/compile3.py https://github.com/commaai/openpilot/raw/v0.9.7/selfdrive/modeld/models/dmonitoring_model.onnx
- name: openpilot compile3 Space Lab policy + vision - name: openpilot compile3 Space Lab policy + vision
run: | run: |
PYTHONPATH="." QCOM=1 taskset -c 4-7 python3 examples/openpilot/compile3.py https://gitlab.com/commaai/openpilot-lfs.git/gitlab-lfs/objects/22aec22a10ce09384d4a4af2a0bbff08d54af7e0c888503508f356fae4ff0e29 PYTHONPATH="." QCOM=1 taskset -c 4-7 python3 examples/openpilot/compile3.py https://gitlab.com/commaai/openpilot-lfs.git/gitlab-lfs/objects/22aec22a10ce09384d4a4af2a0bbff08d54af7e0c888503508f356fae4ff0e29
@@ -690,12 +692,11 @@ jobs:
run: AMD=1 TESTFILE=/raid/downloads/llama3-8b-sfr/model-00001-of-00004.safetensors python3 test/external/external_benchmark_disk_raw.py run: AMD=1 TESTFILE=/raid/downloads/llama3-8b-sfr/model-00001-of-00004.safetensors python3 test/external/external_benchmark_disk_raw.py
- name: Run full CIFAR training w 1 GPU - name: Run full CIFAR training w 1 GPU
run: time BENCHMARK_LOG=cifar AMD=1 DEFAULT_FLOAT=HALF LATEWINO=1 STEPS=1000 TARGET_EVAL_ACC_PCT=93.2 python3 examples/hlb_cifar10.py | tee am_train_cifar_one_gpu.txt run: time BENCHMARK_LOG=cifar AMD=1 DEFAULT_FLOAT=HALF LATEWINO=1 STEPS=1000 TARGET_EVAL_ACC_PCT=93.2 python3 examples/hlb_cifar10.py | tee am_train_cifar_one_gpu.txt
# TODO: enable - name: Run 10 MLPerf ResNet50 training steps (1 gpu)
# - name: Run 10 MLPerf ResNet50 training steps (1 gpu) run: BENCHMARK_LOG=resnet_10steps AMD=1 MNISTMOCK=1 DEFAULT_FLOAT=HALF BENCHMARK=10 BS=256 GPUS=1 MODEL=resnet python3 examples/mlperf/model_train.py | tee am_train_resnet_one_gpu.txt
# run: BENCHMARK_LOG=resnet_10steps AMD=1 MNISTMOCK=1 DEFAULT_FLOAT=HALF BENCHMARK=10 BS=256 GPUS=1 MODEL=resnet python3 examples/mlperf/model_train.py | tee am_train_resnet_one_gpu.txt
- name: Run 10 MLPerf Bert training steps (1 gpu) - name: Run 10 MLPerf Bert training steps (1 gpu)
# TODO: remove BERT_LAYERS once scheduler is fast # TODO: remove BERT_LAYERS once scheduler is fast
run: BENCHMARK_LOG=bert_10steps AMD=1 CAPTURE_PROCESS_REPLAY=0 DEFAULT_FLOAT=HALF BENCHMARK=10 BS=66 GPUS=1 BERT_LAYERS=2 MODEL=bert python3 examples/mlperf/model_train.py | tee am_train_bert_one_gpu.txt run: BENCHMARK_LOG=bert_10steps AMD=1 CAPTURE_PROCESS_REPLAY=0 DEFAULT_FLOAT=HALF BENCHMARK=10 BS=66 GPUS=1 BERT_LAYERS=2 FUSE_ARANGE=1 FUSE_ARANGE_UINT=0 MODEL=bert python3 examples/mlperf/model_train.py | tee am_train_bert_one_gpu.txt
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@v4
with: with:
name: Speed (AM Driver) name: Speed (AM Driver)
@@ -753,7 +754,7 @@ jobs:
run: BENCHMARK_LOG=resnet_10steps NV=1 MNISTMOCK=1 DEFAULT_FLOAT=HALF BENCHMARK=10 BS=256 GPUS=1 MODEL=resnet python3 examples/mlperf/model_train.py | tee nv_train_resnet_one_gpu.txt run: BENCHMARK_LOG=resnet_10steps NV=1 MNISTMOCK=1 DEFAULT_FLOAT=HALF BENCHMARK=10 BS=256 GPUS=1 MODEL=resnet python3 examples/mlperf/model_train.py | tee nv_train_resnet_one_gpu.txt
- name: Run 10 MLPerf Bert training steps (1 gpu) - name: Run 10 MLPerf Bert training steps (1 gpu)
# TODO: remove BERT_LAYERS once scheduler is fast # TODO: remove BERT_LAYERS once scheduler is fast
run: BENCHMARK_LOG=bert_10steps NV=1 CAPTURE_PROCESS_REPLAY=0 DEFAULT_FLOAT=HALF BENCHMARK=10 BS=66 GPUS=1 BERT_LAYERS=2 MODEL=bert python3 examples/mlperf/model_train.py | tee nv_train_bert_one_gpu.txt run: BENCHMARK_LOG=bert_10steps NV=1 CAPTURE_PROCESS_REPLAY=0 DEFAULT_FLOAT=HALF BENCHMARK=10 BS=66 GPUS=1 BERT_LAYERS=2 FUSE_ARANGE=1 FUSE_ARANGE_UINT=0 MODEL=bert python3 examples/mlperf/model_train.py | tee nv_train_bert_one_gpu.txt
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@v4
with: with:
name: Speed (NV Driver) name: Speed (NV Driver)
+25 -48
View File
@@ -1,10 +1,8 @@
name: Unit Tests name: Unit Tests
env: env:
# increment this when downloads substantially change to avoid the internet # increment this when downloads substantially change to avoid the internet
DOWNLOAD_CACHE_VERSION: '12' DOWNLOAD_CACHE_VERSION: '10'
PYTHON_CACHE_VERSION: '3' PYTHON_CACHE_VERSION: '2'
APT_CACHE_VERSION: '1'
BUILD_CACHE_VERSION: '1'
CAPTURE_PROCESS_REPLAY: 1 CAPTURE_PROCESS_REPLAY: 1
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -32,9 +30,9 @@ jobs:
- name: External Benchmark Schedule - name: External Benchmark Schedule
run: PYTHONPATH="." python3 test/external/external_benchmark_schedule.py run: PYTHONPATH="." python3 test/external/external_benchmark_schedule.py
- name: Speed Test - name: Speed Test
run: LLVM=1 python3 test/speed/external_test_speed_v_torch.py run: LLVM=1 python3 test/test_speed_v_torch.py
- name: Speed Test (BEAM=2) - name: Speed Test (BEAM=2)
run: BEAM=2 LLVM=1 python3 test/speed/external_test_speed_v_torch.py run: BEAM=2 LLVM=1 python3 test/test_speed_v_torch.py
docs: docs:
name: Docs name: Docs
@@ -48,11 +46,6 @@ jobs:
with: with:
deps: docs deps: docs
pydeps: "capstone" pydeps: "capstone"
- name: Build wheel and show size
run: |
pip install build
python -m build --wheel --outdir dist
ls -lh dist/*.whl
- name: Use as an external package - name: Use as an external package
run: | run: |
mkdir $HOME/test_external_dir mkdir $HOME/test_external_dir
@@ -336,6 +329,7 @@ jobs:
run: | run: |
pip3 install --upgrade --force-reinstall ruff==0.11.0 pip3 install --upgrade --force-reinstall ruff==0.11.0
python3 -m ruff check . python3 -m ruff check .
python3 -m ruff check extra/onnx.py
python3 -m ruff check examples/mlperf/ --ignore E501 python3 -m ruff check examples/mlperf/ --ignore E501
- name: Lint tinygrad with pylint - name: Lint tinygrad with pylint
run: python -m pylint tinygrad/ run: python -m pylint tinygrad/
@@ -343,6 +337,7 @@ jobs:
run: | run: |
python -m mypy --strict-equality --lineprecision-report . python -m mypy --strict-equality --lineprecision-report .
cat lineprecision.txt cat lineprecision.txt
python -m mypy --strict-equality extra/onnx.py
unittest: unittest:
name: Unit Tests name: Unit Tests
@@ -380,8 +375,8 @@ jobs:
PYTHONPATH=. python extra/optimization/extract_dataset.py PYTHONPATH=. python extra/optimization/extract_dataset.py
gzip -c /tmp/sops > extra/datasets/sops.gz gzip -c /tmp/sops > extra/datasets/sops.gz
DEBUG=1 MIN_ASTS=1 PYTHONPATH=. python extra/optimization/get_action_space.py DEBUG=1 MIN_ASTS=1 PYTHONPATH=. python extra/optimization/get_action_space.py
- name: Repo line count < 17000 lines - name: Repo line count < 15500 lines
run: MAX_LINE_COUNT=17000 python sz.py run: MAX_LINE_COUNT=15500 python sz.py
fuzzing: fuzzing:
name: Fuzzing name: Fuzzing
@@ -460,7 +455,7 @@ jobs:
testopenpilot: testopenpilot:
name: 'openpilot Compile Tests' name: 'openpilot Compile Tests'
runs-on: ubuntu-22.04 runs-on: ubuntu-22.04
timeout-minutes: 15 timeout-minutes: 10
env: env:
IGNORE_OOB: 0 IGNORE_OOB: 0
steps: steps:
@@ -547,8 +542,8 @@ jobs:
run: PYTHONPATH="." GPU=1 IGNORE_BEAM_CACHE=1 python3 -m pytest extra/optimization/test_beam_search.py run: PYTHONPATH="." GPU=1 IGNORE_BEAM_CACHE=1 python3 -m pytest extra/optimization/test_beam_search.py
- name: Test MLPerf stuff - name: Test MLPerf stuff
run: GPU=1 python -m pytest -n=auto test/external/external_test_optim.py test/external/external_test_losses.py test/external/external_test_metrics.py test/external/external_test_datasets.py --durations=20 run: GPU=1 python -m pytest -n=auto test/external/external_test_optim.py test/external/external_test_losses.py test/external/external_test_metrics.py test/external/external_test_datasets.py --durations=20
- name: Test llama 3 training - name: Run handcode_opt
run: MAX_BUFFER_SIZE=0 PYTHONPATH="." DEV=NULL SAMPLES=300 BS=8 SEQLEN=512 GRADIENT_ACC_STEPS=8 FAKEDATA=1 DEFAULT_FLOAT=bfloat16 OPTIM_DTYPE=bfloat16 LLAMA3_SIZE=1B MODEL=llama3 python3 examples/mlperf/model_train.py run: PYTHONPATH=. MODEL=resnet GPU=1 DEBUG=1 BS=4 HALF=0 python3 examples/handcode_opt.py
- name: Run process replay tests - name: Run process replay tests
uses: ./.github/actions/process-replay uses: ./.github/actions/process-replay
@@ -591,29 +586,6 @@ jobs:
- name: Run process replay tests - name: Run process replay tests
uses: ./.github/actions/process-replay uses: ./.github/actions/process-replay
testdevectorize:
name: Linux (devectorize)
runs-on: ubuntu-24.04
timeout-minutes: 15
env:
IGNORE_OOB: 0
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: Setup Environment
uses: ./.github/actions/setup-tinygrad
with:
key: devectorize-minimal
deps: testing_minimal
pydeps: "pillow"
llvm: "true"
- name: Test LLVM=1 DEVECTORIZE=0
run: LLVM=1 DEVECTORIZE=0 python3 -m pytest -n auto test/test_tiny.py test/test_ops.py -k "not test_avg_pool3d_failure"
- name: Test LLVM=1 DEVECTORIZE=0 for model
run: PYTHONPATH="." LLVM=1 DEVECTORIZE=0 python3 test/models/test_efficientnet.py
- name: Test CPU=1 DEVECTORIZE=0
run: CPU=1 DEVECTORIZE=0 FUSE_ARANGE=0 python3 -m pytest -n auto test/test_tiny.py test/test_ops.py -k "not test_avg_pool3d_failure"
testdsp: testdsp:
name: Linux (DSP) name: Linux (DSP)
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
@@ -649,6 +621,12 @@ jobs:
run: CC=clang-20 PYTHONPATH="." DEBUG=2 DSP=1 python test/test_transcendental.py TestTranscendentalVectorized run: CC=clang-20 PYTHONPATH="." DEBUG=2 DSP=1 python test/test_transcendental.py TestTranscendentalVectorized
- name: Test quantize onnx - name: Test quantize onnx
run: PYTHONPATH="." DEBUG=2 DSP=1 python3 test/test_quantize_onnx.py run: PYTHONPATH="." DEBUG=2 DSP=1 python3 test/test_quantize_onnx.py
- name: Test LLVM=1 DEVECTORIZE=0
run: LLVM=1 DEVECTORIZE=0 python3 -m pytest -n auto test/test_tiny.py test/test_ops.py -k "not test_avg_pool3d_failure"
- name: Test LLVM=1 DEVECTORIZE=0 for model
run: PYTHONPATH="." LLVM=1 DEVECTORIZE=0 python3 test/models/test_efficientnet.py
- name: Test CPU=1 DEVECTORIZE=0
run: CPU=1 DEVECTORIZE=0 python3 -m pytest -n auto test/test_tiny.py test/test_ops.py -k "not test_avg_pool3d_failure"
testwebgpu: testwebgpu:
name: Linux (WebGPU) name: Linux (WebGPU)
@@ -708,9 +686,9 @@ jobs:
DEBUG=5 FORWARD_ONLY=1 python3 test/test_ops.py TestOps.test_add DEBUG=5 FORWARD_ONLY=1 python3 test/test_ops.py TestOps.test_add
- name: Run LLVM test - name: Run LLVM test
if: matrix.backend=='amdllvm' if: matrix.backend=='amdllvm'
run: python test/device/test_amd_llvm.py run: python test/test_amd_llvm.py
- name: Run pytest (amd) - name: Run pytest (amd)
run: python -m pytest -n=auto test/test_ops.py test/test_dtype.py test/test_dtype_alu.py test/test_linearizer.py test/test_randomness.py test/test_jit.py test/test_graph.py test/test_multitensor.py test/device/test_hcq.py --durations=20 run: python -m pytest -n=auto test/test_ops.py test/test_dtype.py test/test_dtype_alu.py test/test_linearizer.py test/test_randomness.py test/test_jit.py test/test_graph.py test/test_multitensor.py test/test_hcq.py --durations=20
- name: Run pytest (amd) - name: Run pytest (amd)
run: python -m pytest test/external/external_test_am.py --durations=20 run: python -m pytest test/external/external_test_am.py --durations=20
- name: Run TRANSCENDENTAL math - name: Run TRANSCENDENTAL math
@@ -835,14 +813,14 @@ jobs:
AMD: 1 AMD: 1
FORWARD_ONLY: 1 FORWARD_ONLY: 1
run: | run: |
python3 -m pytest -n=auto test/device/test_hcq.py test/test_tiny.py --durations=20 python3 -m pytest -n=auto test/test_hcq.py test/test_tiny.py --durations=20
- name: Run pytest (amd with llvm backend) - name: Run pytest (amd with llvm backend)
env: env:
MOCKGPU: 1 MOCKGPU: 1
AMD: 1 AMD: 1
FORWARD_ONLY: 1 FORWARD_ONLY: 1
run: | run: |
python -m pytest -n=auto test/device/test_hcq.py test/test_tiny.py test/device/test_amd_llvm.py --durations=20 python -m pytest -n=auto test/test_hcq.py test/test_tiny.py test/test_amd_llvm.py --durations=20
- name: Run pytest (ptx) - name: Run pytest (ptx)
env: env:
MOCKGPU: 1 MOCKGPU: 1
@@ -850,7 +828,7 @@ jobs:
NV: 1 NV: 1
FORWARD_ONLY: 1 FORWARD_ONLY: 1
run: | run: |
python3 -m pytest -n=auto test/device/test_hcq.py test/test_tiny.py --durations=20 python3 -m pytest -n=auto test/test_hcq.py test/test_tiny.py --durations=20
- name: Run process replay tests - name: Run process replay tests
uses: ./.github/actions/process-replay uses: ./.github/actions/process-replay
@@ -961,18 +939,18 @@ jobs:
env: env:
HOST: 127.0.0.1:6667*6,127.0.0.1:6668*6 HOST: 127.0.0.1:6667*6,127.0.0.1:6668*6
run: | run: |
python3 -m pytest test/test_tiny.py test/test_jit.py test/test_subbuffer.py test/test_graph.py test/test_multitensor.py test/test_remote.py test/test_tensor_variable.py --durations 20 python3 -m pytest test/test_tiny.py test/test_jit.py test/test_subbuffer.py test/test_graph.py test/test_multitensor.py test/test_remote.py test/test_tensor_variable.py
- name: Run REMOTE=1 Test (GPU) - name: Run REMOTE=1 Test (GPU)
env: env:
HOST: 127.0.0.1:7667*6 HOST: 127.0.0.1:7667*6
run: | run: |
python3 -m pytest test/test_tiny.py test/test_image_dtype.py test/test_jit.py --durations 20 python3 -m pytest test/test_tiny.py test/test_image_dtype.py test/test_jit.py
IMAGE=2 python3 -m pytest test/test_tiny.py test/test_image_dtype.py IMAGE=2 python3 -m pytest test/test_tiny.py test/test_image_dtype.py
- name: Run REMOTE=1 Test (CPU) - name: Run REMOTE=1 Test (CPU)
env: env:
HOST: 127.0.0.1:8667*6 HOST: 127.0.0.1:8667*6
run: | run: |
python3 -m pytest test/test_tiny.py test/test_jit.py test/test_multitensor.py --durations 20 python3 -m pytest test/test_tiny.py test/test_jit.py test/test_multitensor.py
- name: Show remote server logs - name: Show remote server logs
if: always() if: always()
run: | run: |
@@ -999,7 +977,6 @@ jobs:
with: with:
key: macos-${{ matrix.backend }}-minimal key: macos-${{ matrix.backend }}-minimal
deps: testing_minimal deps: testing_minimal
pydeps: "capstone"
llvm: ${{ matrix.backend == 'llvm' && 'true' }} llvm: ${{ matrix.backend == 'llvm' && 'true' }}
- name: Set env - name: Set env
run: printf "${{ matrix.backend == 'llvm' && 'LLVM=1' || matrix.backend == 'cpu' && 'CPU=1' || matrix.backend == 'metal' && 'METAL=1'}}" >> $GITHUB_ENV run: printf "${{ matrix.backend == 'llvm' && 'LLVM=1' || matrix.backend == 'cpu' && 'CPU=1' || matrix.backend == 'metal' && 'METAL=1'}}" >> $GITHUB_ENV
+24
View File
@@ -198,7 +198,11 @@ generate_amd() {
clang2py -k cdefstum \ clang2py -k cdefstum \
extra/hip_gpu_driver/sdma_registers.h \ extra/hip_gpu_driver/sdma_registers.h \
extra/hip_gpu_driver/nvd.h \ extra/hip_gpu_driver/nvd.h \
extra/hip_gpu_driver/kfd_pm4_headers_ai.h \
extra/hip_gpu_driver/soc21_enum.h \
extra/hip_gpu_driver/sdma_v6_0_0_pkt_open.h \
extra/hip_gpu_driver/gc_11_0_0_offset.h \ extra/hip_gpu_driver/gc_11_0_0_offset.h \
extra/hip_gpu_driver/gc_10_3_0_offset.h \
extra/hip_gpu_driver/sienna_cichlid_ip_offset.h \ extra/hip_gpu_driver/sienna_cichlid_ip_offset.h \
--clang-args="-I/opt/rocm/include -x c++" \ --clang-args="-I/opt/rocm/include -x c++" \
-o $BASE/amd_gpu.py -o $BASE/amd_gpu.py
@@ -372,6 +376,26 @@ generate_am() {
-o $BASE/am/pm4_nv.py -o $BASE/am/pm4_nv.py
fixup $BASE/am/pm4_nv.py fixup $BASE/am/pm4_nv.py
clang2py -k cdefstum \
$AMKERN_INC/vega10_enum.h \
-o $BASE/am/vega10.py
fixup $BASE/am/vega10.py
clang2py -k cdefstum \
$AMKERN_INC/navi10_enum.h \
-o $BASE/am/navi10.py
fixup $BASE/am/navi10.py
clang2py -k cdefstum \
$AMKERN_INC/soc21_enum.h \
-o $BASE/am/soc21.py
fixup $BASE/am/soc21.py
clang2py -k cdefstum \
$AMKERN_INC/soc24_enum.h \
-o $BASE/am/soc24.py
fixup $BASE/am/soc24.py
clang2py -k cdefstum \ clang2py -k cdefstum \
extra/hip_gpu_driver/sdma_registers.h \ extra/hip_gpu_driver/sdma_registers.h \
$AMKERN_AMD/amdgpu/vega10_sdma_pkt_open.h \ $AMKERN_AMD/amdgpu/vega10_sdma_pkt_open.h \
+2 -2
View File
@@ -18,11 +18,11 @@ Group UOps into kernels.
--- ---
## tinygrad/codegen/opt ## tinygrad/opt
Transforms the ast into an optimized ast. This is where BEAM search and heuristics live. Transforms the ast into an optimized ast. This is where BEAM search and heuristics live.
::: tinygrad.codegen.opt.get_optimized_ast ::: tinygrad.opt.get_optimized_ast
options: options:
members: false members: false
show_labels: false show_labels: false
+3 -3
View File
@@ -47,8 +47,8 @@ Reboot after making these changes or restart the `displayservice.service` servic
The [default tinybox image](https://github.com/tinygrad/tinyos) ships with tinygrad and PyTorch. While we develop tinygrad, the box is universal hardware. Use whatever framework you desire, run notebooks, download demos, install more things, train, inference, live, laugh, love, you aren't paying per hour for this box so the only limit is your imagination. The [default tinybox image](https://github.com/tinygrad/tinyos) ships with tinygrad and PyTorch. While we develop tinygrad, the box is universal hardware. Use whatever framework you desire, run notebooks, download demos, install more things, train, inference, live, laugh, love, you aren't paying per hour for this box so the only limit is your imagination.
## Building the OS image ## tinychat
The OS image is built using `ubuntu-image` from <https://github.com/tinygrad/tinyos>. Since LLMs are so popular, we ship with a built in tinygrad based chatbot using a LLaMA-3 finetune. Visit the IP (not the BMC IP) of your tinybox in a web browser on your computer or phone, and you'll find a friendly looking chat interface. This chatbot also provides an OpenAI compatible LLM API on that port, so you can script it.
After cloning, run `make green` or `make red` to build a tinybox green or tinybox red image respectively. The conversations you have with this chatbot are between you and your tinybox. Also, the history in the web app is saved on the client, not the tinybox.
+6 -4
View File
@@ -1,12 +1,12 @@
# model based off https://medium.com/data-science/going-beyond-99-mnist-handwritten-digits-recognition-cfff96337392 # model based off https://medium.com/data-science/going-beyond-99-mnist-handwritten-digits-recognition-cfff96337392
from typing import Callable from typing import List, Callable
from tinygrad import Tensor, TinyJit, nn, GlobalCounters from tinygrad import Tensor, TinyJit, nn, GlobalCounters
from tinygrad.helpers import getenv, colored, trange from tinygrad.helpers import getenv, colored, trange
from tinygrad.nn.datasets import mnist from tinygrad.nn.datasets import mnist
class Model: class Model:
def __init__(self): def __init__(self):
self.layers: list[Callable[[Tensor], Tensor]] = [ self.layers: List[Callable[[Tensor], Tensor]] = [
nn.Conv2d(1, 32, 5), Tensor.relu, nn.Conv2d(1, 32, 5), Tensor.relu,
nn.Conv2d(32, 32, 5), Tensor.relu, nn.Conv2d(32, 32, 5), Tensor.relu,
nn.BatchNorm(32), Tensor.max_pool2d, nn.BatchNorm(32), Tensor.max_pool2d,
@@ -21,15 +21,17 @@ if __name__ == "__main__":
X_train, Y_train, X_test, Y_test = mnist(fashion=getenv("FASHION")) X_train, Y_train, X_test, Y_test = mnist(fashion=getenv("FASHION"))
model = Model() model = Model()
opt = (nn.optim.Adam if not getenv("MUON") else nn.optim.Muon)(nn.state.get_parameters(model)) opt = nn.optim.Adam(nn.state.get_parameters(model))
@TinyJit @TinyJit
@Tensor.train() @Tensor.train()
def train_step() -> Tensor: def train_step() -> Tensor:
opt.zero_grad() opt.zero_grad()
samples = Tensor.randint(getenv("BS", 512), high=X_train.shape[0]) samples = Tensor.randint(getenv("BS", 512), high=X_train.shape[0])
# TODO: this "gather" of samples is very slow. will be under 5s when this is fixed
loss = model(X_train[samples]).sparse_categorical_crossentropy(Y_train[samples]).backward() loss = model(X_train[samples]).sparse_categorical_crossentropy(Y_train[samples]).backward()
return loss.realize(*opt.schedule_step()) opt.step()
return loss
@TinyJit @TinyJit
def get_test_acc() -> Tensor: return (model(X_test).argmax(axis=1) == Y_test).mean()*100 def get_test_acc() -> Tensor: return (model(X_test).argmax(axis=1) == Y_test).mean()*100
+134
View File
@@ -0,0 +1,134 @@
from extra.models.resnet import ResNet50
from extra.mcts_search import mcts_search
from examples.mlperf.helpers import get_mlperf_bert_model
from tinygrad import Tensor, Device, dtypes, nn
from tinygrad.opt.kernel import Kernel
from tinygrad.opt.heuristic import hand_coded_optimizations
from tinygrad.uop.ops import Ops, sym_infer
from tinygrad.device import Compiled
from tinygrad.opt.search import beam_search, bufs_from_lin
from tinygrad.helpers import DEBUG, ansilen, getenv, colored, TRACEMETA
from extra.optimization.helpers import time_linearizer
from tinygrad.engine.realize import get_program
def get_sched_resnet():
mdl = ResNet50()
optim = (nn.optim.LARS if getenv("LARS") else nn.optim.SGD)(nn.state.get_parameters(mdl))
BS = getenv("BS", 64)
# run model twice to get only what changes, these are the kernels of the model
for _ in range(2):
out = mdl(Tensor.empty(BS, 3, 224, 224))
targets = [out]
if getenv("BACKWARD"):
optim.zero_grad()
out.sparse_categorical_crossentropy(Tensor.empty(BS, dtype=dtypes.int)).backward()
targets += [x for x in optim.schedule_step()]
sched = Tensor.schedule(*targets)
print(f"schedule length {len(sched)}")
return sched
def get_sched_bert():
mdl = get_mlperf_bert_model()
optim = nn.optim.LAMB(nn.state.get_parameters(mdl))
# fake data
BS = getenv("BS", 9)
input_ids = Tensor.empty((BS, 512), dtype=dtypes.float32)
segment_ids = Tensor.empty((BS, 512), dtype=dtypes.float32)
attention_mask = Tensor.empty((BS, 512), dtype=dtypes.default_float)
masked_positions = Tensor.empty((BS, 76), dtype=dtypes.float32)
masked_lm_ids = Tensor.empty((BS, 76), dtype=dtypes.float32)
masked_lm_weights = Tensor.empty((BS, 76), dtype=dtypes.float32)
next_sentence_labels = Tensor.empty((BS, 1), dtype=dtypes.float32)
# run model twice to get only what changes, these are the kernels of the model
for _ in range(2):
lm_logits, seq_relationship_logits = mdl(input_ids, attention_mask, masked_positions, segment_ids)
targets = [lm_logits, seq_relationship_logits]
if getenv("BACKWARD"):
optim.zero_grad()
loss = mdl.loss(lm_logits, seq_relationship_logits, masked_lm_ids, masked_lm_weights, next_sentence_labels)
# ignore grad norm and loss scaler for now
loss.backward()
targets += [x for x in optim.schedule_step()]
sched = Tensor.schedule(*targets)
print(f"schedule length {len(sched)}")
return sched
if __name__ == "__main__":
if getenv("HALF", 1):
dtypes.default_float = dtypes.half
# the device we are optimizing for
device: Compiled = Device[Device.DEFAULT]
if getenv("BACKWARD"): Tensor.training = True
print(f"optimizing for {Device.DEFAULT}")
sched = globals()[f"get_sched_{getenv('MODEL', 'resnet')}"]()
sched = [x for x in sched if x.ast.op is Ops.SINK]
# focus on one kernel
if getenv("KERNEL", -1) >= 0: sched = sched[getenv("KERNEL", -1):getenv("KERNEL", -1)+1]
# work with the schedule
total_tm = 0
running_gflops = 0
usage = {}
for i,si in enumerate(sched):
if DEBUG >= 3: print(si.ast)
rawbufs = bufs_from_lin(Kernel(si.ast))
# "linearize" the op into uops in different ways
lins: list[tuple[Kernel, str]] = []
# always try hand coded opt
lin = Kernel(si.ast, opts=device.renderer)
lin.apply_opts(hand_coded_optimizations(lin))
lins.append((lin, "HC"))
# maybe try tensor cores
lin = Kernel(si.ast, opts=device.renderer)
if lin.apply_tensor_cores():
lins.append((lin, "TC"))
# try a beam search
if beam:=getenv("BEAM"):
lin = Kernel(si.ast, opts=device.renderer)
lin = beam_search(lin, rawbufs, beam, bool(getenv("BEAM_ESTIMATE", 1)))
lins.append((lin, "BEAM"))
# try MCTS
if mcts:=getenv("MCTS"):
lin = Kernel(si.ast, opts=device.renderer)
lin = mcts_search(lin, rawbufs, mcts)
lins.append((lin, "MCTS"))
# benchmark the programs
choices = []
for lin, nm in lins:
tm = time_linearizer(lin, rawbufs, allow_test_size=False, cnt=10, disable_cache=True)
ops = (prg:=get_program(lin.get_optimized_ast(), lin.opts)).estimates.ops
gflops = sym_infer(ops, {k:k.min for k in lin.ast.variables()})*1e-9/tm
choices.append((tm, gflops, lin, prg, nm))
sorted_choices = sorted(choices, key=lambda x: x[0])
if DEBUG >= 1: # print all kernels
for tm, gflops, lin, prg, nm in choices:
print(f" kernel {i:2d} {lin.name+' '*(37-ansilen(lin.name))} {str(prg.global_size):18s} {str(prg.local_size):12s} takes {tm*1000:7.2f} ms, {gflops:6.0f} GFLOPS -- {colored(nm, 'green') if lin is sorted_choices[0][2] else nm}")
tm, gflops, lin, prg, nm = sorted_choices[0]
if getenv("SRC"):
print(si.ast)
print(lin.applied_opts)
print(get_program(lin.get_optimized_ast(), lin.opts).src)
total_tm += tm
running_gflops += gflops * tm
if (key := str([str(m) for m in si.metadata])) not in usage: usage[key] = (0, 0)
usage[key] = (usage[key][0] + tm, usage[key][1] + 1)
print(f"*** {total_tm*1000:7.2f} ms : kernel {i:2d} {lin.name+' '*(37-ansilen(lin.name))} {str(prg.global_size):18s} {str(prg.local_size):12s} takes {tm*1000:7.2f} ms, {gflops:6.0f} GFLOPS {[repr(m) if TRACEMETA >= 2 else str(m) for m in si.metadata]}")
print(f"******* total {total_tm*1000:.2f} ms, {running_gflops/total_tm:6.0f} GFLOPS")
print("usage:")
for k in sorted(usage, key=lambda x: -usage[x][0])[:10]:
print(f"{usage[k][0]*1000:.2f} ms: {k} ({usage[k][1]} times)")
+16 -65
View File
@@ -1,4 +1,6 @@
import os, random, pickle, queue, struct, math, functools, hashlib, time import functools
import hashlib
import os, random, pickle, queue, struct, math
from typing import List from typing import List
from pathlib import Path from pathlib import Path
from multiprocessing import Queue, Process, shared_memory, connection, Lock, cpu_count from multiprocessing import Queue, Process, shared_memory, connection, Lock, cpu_count
@@ -530,21 +532,21 @@ class BinIdxDataset:
start = self.idx.tell() start = self.idx.tell()
end = start + self.count * dtypes.int32.itemsize end = start + self.count * dtypes.int32.itemsize
self.sizes = self.idx_t[start:end].bitcast(dtypes.int32).numpy() self.sizes = self.idx_t[start:end].bitcast(dtypes.int32)
start = end start = end
end = start + self.count * dtypes.int64.itemsize end = start + self.count * dtypes.int64.itemsize
self.pointers = self.idx_t[start:end].bitcast(dtypes.int64).numpy() self.pointers = self.idx_t[start:end].bitcast(dtypes.int64)
start = end start = end
end = start + doc_count * dtypes.int64.itemsize end = start + doc_count * dtypes.int64.itemsize
self.doc_idx = self.idx_t[start:end].bitcast(dtypes.int64).numpy() self.doc_idx = self.idx_t[start:end].bitcast(dtypes.int64)
# bin file # bin file
self.bin_t = Tensor(base_path.with_name(f"{base_path.name}.bin")) self.bin_t = Tensor(base_path.with_name(f"{base_path.name}.bin"))
def _index(self, idx) -> tuple[int, int]: def _index(self, idx) -> tuple[int, int]:
return int(self.pointers[idx]), int(self.sizes[idx]) return self.pointers[idx].item(), self.sizes[idx].item()
def get(self, idx, offset:int=0, length:int|None=None): def get(self, idx, offset:int=0, length:int|None=None):
ptr, size = self._index(idx) ptr, size = self._index(idx)
@@ -564,13 +566,10 @@ class GPTDataset:
# check for cache # check for cache
cache_hash = hashlib.sha256(f"{samples}:{seqlen}:{seed}:{shuffle}".encode()).hexdigest() cache_hash = hashlib.sha256(f"{samples}:{seqlen}:{seed}:{shuffle}".encode()).hexdigest()
cache_path = base_path.with_name(f"{base_path.name}.{cache_hash}.index_cache") cache_path = base_path.with_name(f"{base_path.name}.{cache_hash}.index_cache")
print(f"try loading GPTDataset from {cache_path}...")
if cache_path.exists(): if cache_path.exists():
print("cache found, loading...")
with open(cache_path, "rb") as f: with open(cache_path, "rb") as f:
self.doc_idx, self.sample_idx, self.shuffle_idx = pickle.load(f) self.doc_idx, self.sample_idx, self.shuffle_idx = pickle.load(f)
else: else:
print("cache not found, building index...")
self.doc_idx = self._build_doc_idx() self.doc_idx = self._build_doc_idx()
self.sample_idx = self._build_sample_idx() self.sample_idx = self._build_sample_idx()
self.shuffle_idx = self._build_shuffle_idx() self.shuffle_idx = self._build_shuffle_idx()
@@ -629,20 +628,14 @@ class GPTDataset:
# https://github.com/NVIDIA/Megatron-LM/blob/94bd476bd840c2fd4c3ebfc7448c2af220f4832b/megatron/core/datasets/gpt_dataset.py#L558 # https://github.com/NVIDIA/Megatron-LM/blob/94bd476bd840c2fd4c3ebfc7448c2af220f4832b/megatron/core/datasets/gpt_dataset.py#L558
def _build_doc_idx(self): def _build_doc_idx(self):
print(f"building doc_idx for {self.num_epochs=}, {self.indexed_dataset.count=}") doc_idx = np.mgrid[:self.num_epochs, :self.indexed_dataset.count][1]
st = time.perf_counter() doc_idx = doc_idx.reshape(-1)
# doc_idx = np.mgrid[:self.num_epochs, :self.indexed_dataset.count][1]
doc_idx = np.arange(self.indexed_dataset.count).reshape(1, -1).repeat(self.num_epochs, axis=0).flatten()
doc_idx = doc_idx.astype(np.int32) doc_idx = doc_idx.astype(np.int32)
at = time.perf_counter()
if self.shuffle: self.rng.shuffle(doc_idx) if self.shuffle: self.rng.shuffle(doc_idx)
print(f"doc_idx built in {at - st:.3f}s, shuffled in {time.perf_counter() - at:.3f}s")
return doc_idx return doc_idx
def _build_sample_idx(self): def _build_sample_idx(self):
print(f"building sample_idx for {self.samples=}, {self.seqlen=}, {self.doc_idx.shape[0]=}") sample_idx = np.empty((self.samples + 1, 2), dtype=np.int32)
sample_idx_max = max(self.doc_idx.shape[0], self.indexed_dataset.sizes.max())
sample_idx = np.empty((self.samples + 1, 2), dtype=np.int64 if sample_idx_max > dtypes.int32.max else np.int32)
sample_idx_idx, doc_idx_idx, doc_offset = 0, 0, 0 sample_idx_idx, doc_idx_idx, doc_offset = 0, 0, 0
sample_idx[sample_idx_idx, 0], sample_idx[sample_idx_idx, 1] = doc_idx_idx, doc_offset sample_idx[sample_idx_idx, 0], sample_idx[sample_idx_idx, 1] = doc_idx_idx, doc_offset
@@ -652,7 +645,7 @@ class GPTDataset:
remaining_seqlen = self.seqlen + 1 remaining_seqlen = self.seqlen + 1
while remaining_seqlen > 0: while remaining_seqlen > 0:
doc_idx = int(self.doc_idx[doc_idx_idx]) doc_idx = int(self.doc_idx[doc_idx_idx])
doc_len = int(self.indexed_dataset.sizes[doc_idx]) - doc_offset doc_len = self.indexed_dataset.sizes[doc_idx].item() - doc_offset
remaining_seqlen -= doc_len remaining_seqlen -= doc_len
if remaining_seqlen <= 0: if remaining_seqlen <= 0:
doc_offset += remaining_seqlen + doc_len - 1 doc_offset += remaining_seqlen + doc_len - 1
@@ -661,7 +654,7 @@ class GPTDataset:
if doc_idx_idx == len(self.doc_idx) - 1: if doc_idx_idx == len(self.doc_idx) - 1:
assert sample_idx_idx == self.samples assert sample_idx_idx == self.samples
doc_idx = int(self.doc_idx[doc_idx_idx]) doc_idx = int(self.doc_idx[doc_idx_idx])
doc_offset = int(self.indexed_dataset.sizes[doc_idx]) - 1 doc_offset = self.indexed_dataset.sizes[doc_idx].item() - 1
break break
doc_idx_idx += 1 doc_idx_idx += 1
doc_offset = 0 doc_offset = 0
@@ -672,18 +665,13 @@ class GPTDataset:
return sample_idx return sample_idx
def _build_shuffle_idx(self): def _build_shuffle_idx(self):
print(f"building shuffle_idx for {self.samples=}")
st = time.perf_counter()
shuffle_idx = np.arange(self.samples, dtype=np.int32) shuffle_idx = np.arange(self.samples, dtype=np.int32)
at = time.perf_counter()
if self.shuffle: self.rng.shuffle(shuffle_idx) if self.shuffle: self.rng.shuffle(shuffle_idx)
print(f"shuffle_idx built in {at - st:.3f}s, shuffled in {time.perf_counter() - at:.3f}s")
return shuffle_idx return shuffle_idx
class BlendedGPTDataset: class BlendedGPTDataset:
def __init__(self, paths:list[Path], weights:list[float], samples:int, seqlen:int, seed:int, shuffle:bool): def __init__(self, paths:list[Path], weights:list[float], samples:int, seqlen:int, seed:int, shuffle:bool):
self.shuffle = shuffle self.seed = seed
self.rng = np.random.RandomState(seed)
# normalize weights # normalize weights
total_weight = sum(weights) total_weight = sum(weights)
@@ -695,47 +683,10 @@ class BlendedGPTDataset:
self.datasets = [GPTDataset(path, samples_per_blend[i], seqlen, seed + i, shuffle) for i,path in enumerate(paths)] self.datasets = [GPTDataset(path, samples_per_blend[i], seqlen, seed + i, shuffle) for i,path in enumerate(paths)]
# check for cache
cache_hash = hashlib.sha256(f"{samples}:{seqlen}:{seed}:{shuffle}".encode()).hexdigest()
cache_path = paths[0].with_name(f"{paths[0].name}.{cache_hash}.blend_cache")
print(f"try loading BlendedGPTDataset from {cache_path}...")
if cache_path.exists():
print("cache found, loading...")
with open(cache_path, "rb") as f:
self.dataset_idx, self.dataset_sample_idx = pickle.load(f)
else:
print("cache not found, building index...")
self.dataset_idx, self.dataset_sample_idx = self._build_blend_idx()
# save cache
with open(cache_path, "wb") as f:
pickle.dump((self.dataset_idx, self.dataset_sample_idx), f)
def get(self, idx:int): def get(self, idx:int):
tokens = self.datasets[self.dataset_idx[idx]][self.dataset_sample_idx[idx]] tokens = self.datasets[0][idx]
return tokens return tokens
def _build_blend_idx(self):
dataset_idx = np.zeros(self.samples, dtype=np.int16)
dataset_sample_idx = np.zeros(self.samples, dtype=np.int64)
unspent_datasets = set(range(len(self.datasets)))
dataset_sample_counts = [0] * len(self.datasets)
for i in tqdm(range(self.samples)):
error_argmax, error_max = 0, 0.0
for di in unspent_datasets:
error = self.weights[di] * max(i, 1) - dataset_sample_counts[di]
if error > error_max:
error_max = error
error_argmax = di
dataset_idx[i] = error_argmax
dataset_sample_idx[i] = dataset_sample_counts[error_argmax]
dataset_sample_counts[error_argmax] += 1
return dataset_idx, dataset_sample_idx
def batch_load_llama3(bs:int, samples:int, seqlen:int, base_dir:Path, seed:int=0, val:bool=True): def batch_load_llama3(bs:int, samples:int, seqlen:int, base_dir:Path, seed:int=0, val:bool=True):
if val: if val:
dataset = BlendedGPTDataset([ dataset = BlendedGPTDataset([
@@ -788,8 +739,8 @@ if __name__ == "__main__":
def load_llama3(val): def load_llama3(val):
bs = 24 bs = 24
samples = 5760 if val else 1_200_000 * 1152 samples = 5760 if val else 1_200_000
seqlen = 8192 seqlen = 512
max_, min_ = 0, math.inf max_, min_ = 0, math.inf
for tokens in tqdm(batch_load_llama3(bs, samples, seqlen, Path(getenv("BASEDIR", "/raid/datasets/c4/")), seed=5760, val=bool(val)), total=samples//bs): for tokens in tqdm(batch_load_llama3(bs, samples, seqlen, Path(getenv("BASEDIR", "/raid/datasets/c4/")), seed=5760, val=bool(val)), total=samples//bs):
+21 -29
View File
@@ -1296,7 +1296,7 @@ def train_llama3():
SEED = config["SEED"] = getenv("SEED", 5760) SEED = config["SEED"] = getenv("SEED", 5760)
SEQLEN = config["SEQLEN"] = getenv("SEQLEN", 8192) SEQLEN = config["SEQLEN"] = getenv("SEQLEN", 8192)
TRAIN_ON_VAL = config["TRAIN_ON_VAL"] = getenv("TRAIN_ON_VAL", 0) TRAIN_ON_VAL = config["TRAIN_ON_VAL"] = getenv("TRAIN_ON_VAL", 0)
SAMPLES = config["SAMPLES"] = getenv("SAMPLES", 5_760 if TRAIN_ON_VAL else 1_200_000 * 1152) SAMPLES = config["SAMPLES"] = getenv("SAMPLES", 5_760 if TRAIN_ON_VAL else 1_200_000)
# LR=1e-4 TRAIN_ON_VAL=1 DEFAULT_FLOAT=bfloat16 FUSE_ARANGE=1 JITBEAM=2 OPTIM_DTYPE=bfloat16 LLAMA3_SIZE=1B WARMUP_STEPS=36 DECAY_STEPS=360 SEQLEN=512 PYTHONPATH=. AMD=1 AMD_LLVM=0 MODEL=llama3 python3 examples/mlperf/model_train.py # LR=1e-4 TRAIN_ON_VAL=1 DEFAULT_FLOAT=bfloat16 FUSE_ARANGE=1 JITBEAM=2 OPTIM_DTYPE=bfloat16 LLAMA3_SIZE=1B WARMUP_STEPS=36 DECAY_STEPS=360 SEQLEN=512 PYTHONPATH=. AMD=1 AMD_LLVM=0 MODEL=llama3 python3 examples/mlperf/model_train.py
# trains to 7 # trains to 7
@@ -1318,33 +1318,29 @@ def train_llama3():
if (llama_layers:=getenv("LLAMA_LAYERS")) != 0: params['n_layers'] = llama_layers if (llama_layers:=getenv("LLAMA_LAYERS")) != 0: params['n_layers'] = llama_layers
model = Transformer(**params, max_context=SEQLEN, jit=False, disable_kv_cache=True) model = Transformer(**params, max_context=SEQLEN, jit=False, disable_kv_cache=True)
if getenv("FAKEDATA"):
for v in get_parameters(model):
v = v.assign(Tensor.empty(v.shape))
if (DP := getenv("DP", 1)) > 1: if (DP := getenv("DP", 1)) > 1:
device = tuple(f"{Device.DEFAULT}:{i}" for i in range(DP)) device = tuple(f"{Device.DEFAULT}:{i}" for i in range(DP))
for v in get_parameters(model): for v in get_parameters(model):
v.shard_(device, axis=None) v.shard_(device, axis=None)
if (MP := getenv("MP", 1)) > 1: # TODO: MP
device = tuple(f"{Device.DEFAULT}:{i}" for i in range(MP)) # if (GPUS := getenv("GPUS", 1)) > 1:
for k,v in get_state_dict(model).items(): # device = tuple(f"{Device.DEFAULT}:{i}" for i in range(GPUS))
if 'scale' in k: v.shard_(device, axis=None) # from quantized # for k,v in get_state_dict(model).items():
elif '.attention.wq' in k: v.shard_(device, axis=0) # if 'scale' in k: v.shard_(device, axis=None) # from quantized
elif '.attention.wk' in k: v.shard_(device, axis=0) # # elif '.attention.wq' in k: v.shard_(device, axis=0)
elif '.attention.wv' in k: v.shard_(device, axis=0) # # elif '.attention.wk' in k: v.shard_(device, axis=0)
elif '.attention.wo' in k: v.shard_(device, axis=1) # # elif '.attention.wv' in k: v.shard_(device, axis=0)
elif '.feed_forward.w1.' in k: v.shard_(device, axis=0) # # elif '.attention.wo' in k: v.shard_(device, axis=1)
elif '.feed_forward.w2.' in k: v.shard_(device, axis=1) # # elif '.feed_forward.w1.' in k: v.shard_(device, axis=0)
elif '.feed_forward.w3.' in k: v.shard_(device, axis=0) # # elif '.feed_forward.w2.' in k: v.shard_(device, axis=1)
elif 'tok_embeddings.weight' in k: v.shard_(device, axis=0) # # elif '.feed_forward.w3.' in k: v.shard_(device, axis=0)
elif 'output.weight' in k: v.shard_(device, axis=0) # # elif 'tok_embeddings.weight' in k: v.shard_(device, axis=0)
else: # elif 'output.weight' in k: v.shard_(device, axis=0) # 243.32
# attention_norm, ffn_norm, norm # else:
v.shard_(device, axis=None) # # print(k)
# prevents memory spike on device 0 # # attention_norm, ffn_norm, norm
v.realize() # v.shard_(device, axis=None)
optim = AdamW(get_parameters(model), lr=0.0, optim = AdamW(get_parameters(model), lr=0.0,
b1=opt_adamw_beta_1, b2=opt_adamw_beta_2, eps=opt_adamw_epsilon, weight_decay=opt_adamw_weight_decay) b1=opt_adamw_beta_1, b2=opt_adamw_beta_2, eps=opt_adamw_epsilon, weight_decay=opt_adamw_weight_decay)
@@ -1359,9 +1355,6 @@ def train_llama3():
if (DP := getenv("DP", 1)) > 1: if (DP := getenv("DP", 1)) > 1:
device = tuple(f"{Device.DEFAULT}:{i}" for i in range(DP)) device = tuple(f"{Device.DEFAULT}:{i}" for i in range(DP))
batch = batch.shard(device, 0) batch = batch.shard(device, 0)
if (MP := getenv("MP", 1)) > 1:
device = tuple(f"{Device.DEFAULT}:{i}" for i in range(MP))
batch = batch.shard(device)
logits:Tensor = model(batch[:, :-1], start_pos=0, temperature=math.nan) logits:Tensor = model(batch[:, :-1], start_pos=0, temperature=math.nan)
loss = logits.sparse_categorical_crossentropy(batch[:, 1:]) loss = logits.sparse_categorical_crossentropy(batch[:, 1:])
loss.backward() loss.backward()
@@ -1398,12 +1391,11 @@ def train_llama3():
t = time.perf_counter() t = time.perf_counter()
GlobalCounters.reset() GlobalCounters.reset()
loss, lr = train_step(model, tokens, grad_acc) loss, lr = train_step(model, tokens, grad_acc)
loss = loss.float().item()
# above as tqdm.write f-string # above as tqdm.write f-string
tqdm.write(f"{loss:.4f} loss, {lr.item():.12f} LR, {GlobalCounters.mem_used / 1e9:.2f} GB used, {time.perf_counter()-t:.2f} s") tqdm.write(f"{loss.item():.4f} loss, {lr.item():.12f} LR, {GlobalCounters.mem_used / 1e9:.2f} GB used, {time.perf_counter()-t:.2f} s")
if (fname:=getenv("LOSS_FILE", "")): if (fname:=getenv("LOSS_FILE", "")):
with open(fname, "a") as f: with open(fname, "a") as f:
f.write(f"{i} {loss:.4f} {lr.item():.12f} {GlobalCounters.mem_used / 1e9:.2f}\n") f.write(f"{i} {loss.item():.4f} {lr.item():.12f} {GlobalCounters.mem_used / 1e9:.2f}\n")
if getenv("CKPT") and (i % 200 == 0 or i == 10): if getenv("CKPT") and (i % 200 == 0 or i == 10):
tqdm.write("saving checkpoint") tqdm.write("saving checkpoint")
@@ -4,8 +4,6 @@ export PYTHONPATH="." AMD=1
export MODEL="bert" export MODEL="bert"
export DEFAULT_FLOAT="HALF" GPUS=1 BS=128 EVAL_BS=128 export DEFAULT_FLOAT="HALF" GPUS=1 BS=128 EVAL_BS=128
export IGNORE_OOB=1
export BEAM=3 BEAM_UOPS_MAX=4000 BEAM_UPCAST_MAX=256 BEAM_LOCAL_MAX=1024 BEAM_MIN_PROGRESS=5 export BEAM=3 BEAM_UOPS_MAX=4000 BEAM_UPCAST_MAX=256 BEAM_LOCAL_MAX=1024 BEAM_MIN_PROGRESS=5
export IGNORE_JIT_FIRST_BEAM=1 export IGNORE_JIT_FIRST_BEAM=1
# export BEAM_LOG_SURPASS_MAX=1 # export BEAM_LOG_SURPASS_MAX=1
@@ -5,8 +5,6 @@ export MODEL="bert"
export DEFAULT_FLOAT="HALF" GPUS=8 BS=1024 EVAL_BS=1024 export DEFAULT_FLOAT="HALF" GPUS=8 BS=1024 EVAL_BS=1024
export OPT_BASE_LEARNING_RATE=0.0011 OPT_LAMB_BETA_1=0.60466 OPT_LAMB_BETA_2=0.85437 DECAY=0.1 export OPT_BASE_LEARNING_RATE=0.0011 OPT_LAMB_BETA_1=0.60466 OPT_LAMB_BETA_2=0.85437 DECAY=0.1
export IGNORE_OOB=1
export BEAM=3 BEAM_UOPS_MAX=6000 BEAM_UPCAST_MAX=256 BEAM_LOCAL_MAX=1024 BEAM_MIN_PROGRESS=5 export BEAM=3 BEAM_UOPS_MAX=6000 BEAM_UPCAST_MAX=256 BEAM_LOCAL_MAX=1024 BEAM_MIN_PROGRESS=5
export IGNORE_JIT_FIRST_BEAM=1 FREE_INTERMEDIATE=0 export IGNORE_JIT_FIRST_BEAM=1 FREE_INTERMEDIATE=0
export BASEDIR="/raid/datasets/wiki" export BASEDIR="/raid/datasets/wiki"
@@ -8,8 +8,6 @@ export DEFAULT_FLOAT="HALF" GPUS=8 BS=1024 EVAL_BS=1024
export OPT_BASE_LEARNING_RATE=0.0011 OPT_LAMB_BETA_1=0.60466 OPT_LAMB_BETA_2=0.85437 DECAY=0.1 export OPT_BASE_LEARNING_RATE=0.0011 OPT_LAMB_BETA_1=0.60466 OPT_LAMB_BETA_2=0.85437 DECAY=0.1
export TRAIN_STEPS=3900 export TRAIN_STEPS=3900
export IGNORE_OOB=1
export BEAM=3 BEAM_UOPS_MAX=6000 BEAM_UPCAST_MAX=256 BEAM_LOCAL_MAX=1024 BEAM_MIN_PROGRESS=5 export BEAM=3 BEAM_UOPS_MAX=6000 BEAM_UPCAST_MAX=256 BEAM_LOCAL_MAX=1024 BEAM_MIN_PROGRESS=5
export IGNORE_JIT_FIRST_BEAM=1 FREE_INTERMEDIATE=0 export IGNORE_JIT_FIRST_BEAM=1 FREE_INTERMEDIATE=0
export BASEDIR="/raid/datasets/wiki" export BASEDIR="/raid/datasets/wiki"
@@ -11,8 +11,6 @@ export DEFAULT_FLOAT="HALF" GPUS=8 BS=1024 EVAL_BS=1024
export OPT_BASE_LEARNING_RATE=0.0011 OPT_LAMB_BETA_1=0.60466 OPT_LAMB_BETA_2=0.85437 DECAY=0.1 export OPT_BASE_LEARNING_RATE=0.0011 OPT_LAMB_BETA_1=0.60466 OPT_LAMB_BETA_2=0.85437 DECAY=0.1
export TRAIN_STEPS=3900 export TRAIN_STEPS=3900
export IGNORE_OOB=1
export BEAM=3 BEAM_UOPS_MAX=6000 BEAM_UPCAST_MAX=256 BEAM_LOCAL_MAX=1024 BEAM_MIN_PROGRESS=5 export BEAM=3 BEAM_UOPS_MAX=6000 BEAM_UPCAST_MAX=256 BEAM_LOCAL_MAX=1024 BEAM_MIN_PROGRESS=5
export IGNORE_JIT_FIRST_BEAM=1 FREE_INTERMEDIATE=0 export IGNORE_JIT_FIRST_BEAM=1 FREE_INTERMEDIATE=0
export BASEDIR="/raid/datasets/wiki" export BASEDIR="/raid/datasets/wiki"
@@ -2,9 +2,9 @@
export PYTHONPATH="." NV=1 export PYTHONPATH="." NV=1
export MODEL="bert" export MODEL="bert"
export DEFAULT_FLOAT="HALF" SUM_DTYPE="HALF" GPUS=6 BS=90 EVAL_BS=90 export DEFAULT_FLOAT="HALF" SUM_DTYPE="HALF" GPUS=6 BS=96 EVAL_BS=96
export IGNORE_OOB=1 export FUSE_ARANGE=1 FUSE_ARANGE_UINT=0
export BEAM=8 BEAM_UOPS_MAX=10000 BEAM_UPCAST_MAX=256 BEAM_LOCAL_MAX=1024 BEAM_MIN_PROGRESS=5 export BEAM=8 BEAM_UOPS_MAX=10000 BEAM_UPCAST_MAX=256 BEAM_LOCAL_MAX=1024 BEAM_MIN_PROGRESS=5
export IGNORE_JIT_FIRST_BEAM=1 export IGNORE_JIT_FIRST_BEAM=1
@@ -2,9 +2,9 @@
export PYTHONPATH="." NV=1 export PYTHONPATH="." NV=1
export MODEL="bert" export MODEL="bert"
export DEFAULT_FLOAT="HALF" SUM_DTYPE="HALF" GPUS=6 BS=90 EVAL_BS=90 export DEFAULT_FLOAT="HALF" SUM_DTYPE="HALF" GPUS=6 BS=96 EVAL_BS=96
export IGNORE_OOB=1 export FUSE_ARANGE=1 FUSE_ARANGE_UINT=0
export BEAM=8 BEAM_UOPS_MAX=10000 BEAM_UPCAST_MAX=256 BEAM_LOCAL_MAX=1024 BEAM_MIN_PROGRESS=5 export BEAM=8 BEAM_UOPS_MAX=10000 BEAM_UPCAST_MAX=256 BEAM_LOCAL_MAX=1024 BEAM_MIN_PROGRESS=5
export IGNORE_JIT_FIRST_BEAM=1 export IGNORE_JIT_FIRST_BEAM=1
@@ -5,9 +5,9 @@ set -o pipefail # Make pipeline fail if any command fails
export PYTHONPATH="." NV=1 export PYTHONPATH="." NV=1
export MODEL="bert" export MODEL="bert"
export SUBMISSION_PLATFORM="tinybox_green" export SUBMISSION_PLATFORM="tinybox_green"
export DEFAULT_FLOAT="HALF" SUM_DTYPE="HALF" GPUS=6 BS=90 EVAL_BS=90 export DEFAULT_FLOAT="HALF" SUM_DTYPE="HALF" GPUS=6 BS=96 EVAL_BS=96
export IGNORE_OOB=1 export FUSE_ARANGE=1 FUSE_ARANGE_UINT=0
export BEAM=8 BEAM_UOPS_MAX=10000 BEAM_UPCAST_MAX=256 BEAM_LOCAL_MAX=1024 BEAM_MIN_PROGRESS=5 export BEAM=8 BEAM_UOPS_MAX=10000 BEAM_UPCAST_MAX=256 BEAM_LOCAL_MAX=1024 BEAM_MIN_PROGRESS=5
export IGNORE_JIT_FIRST_BEAM=1 export IGNORE_JIT_FIRST_BEAM=1
@@ -2,9 +2,9 @@
export PYTHONPATH="." AMD=1 export PYTHONPATH="." AMD=1
export MODEL="bert" export MODEL="bert"
export DEFAULT_FLOAT="HALF" SUM_DTYPE="HALF" GPUS=6 BS=90 EVAL_BS=90 export DEFAULT_FLOAT="HALF" SUM_DTYPE="HALF" GPUS=6 BS=96 EVAL_BS=96
export IGNORE_OOB=1 export FUSE_ARANGE=1 FUSE_ARANGE_UINT=0
export BEAM=5 BEAM_UOPS_MAX=8000 BEAM_UPCAST_MAX=256 BEAM_LOCAL_MAX=1024 BEAM_MIN_PROGRESS=5 export BEAM=5 BEAM_UOPS_MAX=8000 BEAM_UPCAST_MAX=256 BEAM_LOCAL_MAX=1024 BEAM_MIN_PROGRESS=5
export IGNORE_JIT_FIRST_BEAM=1 export IGNORE_JIT_FIRST_BEAM=1
@@ -2,9 +2,9 @@
export PYTHONPATH="." AMD=1 export PYTHONPATH="." AMD=1
export MODEL="bert" export MODEL="bert"
export DEFAULT_FLOAT="HALF" SUM_DTYPE="HALF" GPUS=6 BS=90 EVAL_BS=90 export DEFAULT_FLOAT="HALF" SUM_DTYPE="HALF" GPUS=6 BS=96 EVAL_BS=96
export IGNORE_OOB=1 export FUSE_ARANGE=1 FUSE_ARANGE_UINT=0
export BEAM=5 BEAM_UOPS_MAX=8000 BEAM_UPCAST_MAX=256 BEAM_LOCAL_MAX=1024 BEAM_MIN_PROGRESS=5 export BEAM=5 BEAM_UOPS_MAX=8000 BEAM_UPCAST_MAX=256 BEAM_LOCAL_MAX=1024 BEAM_MIN_PROGRESS=5
export IGNORE_JIT_FIRST_BEAM=1 export IGNORE_JIT_FIRST_BEAM=1
@@ -5,9 +5,9 @@ set -o pipefail # Make pipeline fail if any command fails
export PYTHONPATH="." AMD=1 export PYTHONPATH="." AMD=1
export MODEL="bert" export MODEL="bert"
export SUBMISSION_PLATFORM="tinybox_red" export SUBMISSION_PLATFORM="tinybox_red"
export DEFAULT_FLOAT="HALF" SUM_DTYPE="HALF" GPUS=6 BS=90 EVAL_BS=90 export DEFAULT_FLOAT="HALF" SUM_DTYPE="HALF" GPUS=6 BS=96 EVAL_BS=96
export IGNORE_OOB=1 export FUSE_ARANGE=1 FUSE_ARANGE_UINT=0
export BEAM=5 BEAM_UOPS_MAX=8000 BEAM_UPCAST_MAX=256 BEAM_LOCAL_MAX=1024 BEAM_MIN_PROGRESS=5 export BEAM=5 BEAM_UOPS_MAX=8000 BEAM_UPCAST_MAX=256 BEAM_LOCAL_MAX=1024 BEAM_MIN_PROGRESS=5
export IGNORE_JIT_FIRST_BEAM=1 export IGNORE_JIT_FIRST_BEAM=1
+4 -3
View File
@@ -1,7 +1,8 @@
# https://arxiv.org/pdf/2409.02060 # https://arxiv.org/pdf/2409.02060
import time, functools import time
import numpy as np import numpy as np
np.set_printoptions(suppress=True, linewidth=1000) np.set_printoptions(suppress=True, linewidth=1000)
import functools
from tinygrad import Tensor, nn, Device, GlobalCounters from tinygrad import Tensor, nn, Device, GlobalCounters
from tinygrad.helpers import Timing, getenv from tinygrad.helpers import Timing, getenv
from extra.models.llama import Transformer, convert_from_huggingface from extra.models.llama import Transformer, convert_from_huggingface
@@ -16,7 +17,7 @@ class MixtureFeedForward:
def __call__(self, x:Tensor) -> Tensor: def __call__(self, x:Tensor) -> Tensor:
assert x.shape[0] == 1, "only BS=1" assert x.shape[0] == 1, "only BS=1"
assert x.shape[1] == 1, "only length=1" assert x.shape[1] == 1, "only length=1"
g = self.gate(x).softmax(-1) g = self.gate(x).float().softmax(-1)
g = g.squeeze() # (BS, length, num_experts) -> (num_experts,) g = g.squeeze() # (BS, length, num_experts) -> (num_experts,)
probs, sel = g.topk(self.activated_experts) probs, sel = g.topk(self.activated_experts)
@@ -24,7 +25,7 @@ class MixtureFeedForward:
# run MoE # run MoE
x_up_gate = x.dot(self.gate_proj[sel].permute(0,2,1)).silu() * x.dot(self.up_proj[sel].permute(0,2,1)) x_up_gate = x.dot(self.gate_proj[sel].permute(0,2,1)).silu() * x.dot(self.up_proj[sel].permute(0,2,1))
x_down = x_up_gate.dot(self.down_proj[sel].permute(0,2,1)) x_down = x_up_gate.dot(self.down_proj[sel].permute(0,2,1))
return (x_down * probs.reshape(self.activated_experts, 1, 1)).sum(axis=0) return (x_down.float() * probs.reshape(self.activated_experts, 1, 1)).sum(axis=0)
# model is bf16, 1.3B active, 6.9B total # model is bf16, 1.3B active, 6.9B total
# M3 Max is 400 GB/s, so 400/2.6 = ~154 tok/s # M3 Max is 400 GB/s, so 400/2.6 = ~154 tok/s
+9 -9
View File
@@ -71,8 +71,8 @@ def bbox_iou(box1, box2):
# get the coordinates of the intersection rectangle # get the coordinates of the intersection rectangle
inter_rect_x1 = np.maximum(b1_x1, b2_x1) inter_rect_x1 = np.maximum(b1_x1, b2_x1)
inter_rect_y1 = np.maximum(b1_y1, b2_y1) inter_rect_y1 = np.maximum(b1_y1, b2_y1)
inter_rect_x2 = np.minimum(b1_x2, b2_x2) inter_rect_x2 = np.maximum(b1_x2, b2_x2)
inter_rect_y2 = np.minimum(b1_y2, b2_y2) inter_rect_y2 = np.maximum(b1_y2, b2_y2)
#Intersection area #Intersection area
inter_area = np.clip(inter_rect_x2 - inter_rect_x1 + 1, 0, 99999) * np.clip(inter_rect_y2 - inter_rect_y1 + 1, 0, 99999) inter_area = np.clip(inter_rect_x2 - inter_rect_x1 + 1, 0, 99999) * np.clip(inter_rect_y2 - inter_rect_y1 + 1, 0, 99999)
#Union Area #Union Area
@@ -297,13 +297,13 @@ class Darknet:
# Get the number of weights of batchnorm # Get the number of weights of batchnorm
num_bn_biases = math.prod(bn.bias.shape) num_bn_biases = math.prod(bn.bias.shape)
# Load weights # Load weights
bn_biases = Tensor(weights[ptr:ptr + num_bn_biases].astype(np.float32)) bn_biases = Tensor(weights[ptr:ptr + num_bn_biases])
ptr += num_bn_biases ptr += num_bn_biases
bn_weights = Tensor(weights[ptr:ptr+num_bn_biases].astype(np.float32)) bn_weights = Tensor(weights[ptr:ptr+num_bn_biases])
ptr += num_bn_biases ptr += num_bn_biases
bn_running_mean = Tensor(weights[ptr:ptr+num_bn_biases].astype(np.float32)) bn_running_mean = Tensor(weights[ptr:ptr+num_bn_biases])
ptr += num_bn_biases ptr += num_bn_biases
bn_running_var = Tensor(weights[ptr:ptr+num_bn_biases].astype(np.float32)) bn_running_var = Tensor(weights[ptr:ptr+num_bn_biases])
ptr += num_bn_biases ptr += num_bn_biases
# Cast the loaded weights into dims of model weights # Cast the loaded weights into dims of model weights
bn_biases = bn_biases.reshape(shape=tuple(bn.bias.shape)) bn_biases = bn_biases.reshape(shape=tuple(bn.bias.shape))
@@ -319,7 +319,7 @@ class Darknet:
# load biases of the conv layer # load biases of the conv layer
num_biases = math.prod(conv.bias.shape) num_biases = math.prod(conv.bias.shape)
# Load weights # Load weights
conv_biases = Tensor(weights[ptr: ptr+num_biases].astype(np.float32)) conv_biases = Tensor(weights[ptr: ptr+num_biases])
ptr += num_biases ptr += num_biases
# Reshape # Reshape
conv_biases = conv_biases.reshape(shape=tuple(conv.bias.shape)) conv_biases = conv_biases.reshape(shape=tuple(conv.bias.shape))
@@ -327,7 +327,7 @@ class Darknet:
conv.bias = conv_biases conv.bias = conv_biases
# Load weighys for conv layers # Load weighys for conv layers
num_weights = math.prod(conv.weight.shape) num_weights = math.prod(conv.weight.shape)
conv_weights = Tensor(weights[ptr:ptr+num_weights].astype(np.float32)) conv_weights = Tensor(weights[ptr:ptr+num_weights])
ptr += num_weights ptr += num_weights
conv_weights = conv_weights.reshape(shape=tuple(conv.weight.shape)) conv_weights = conv_weights.reshape(shape=tuple(conv.weight.shape))
conv.weight = conv_weights conv.weight = conv_weights
@@ -371,7 +371,7 @@ class Darknet:
if __name__ == "__main__": if __name__ == "__main__":
model = Darknet(fetch('https://raw.githubusercontent.com/pjreddie/darknet/master/cfg/yolov3.cfg').read_bytes()) model = Darknet(fetch('https://raw.githubusercontent.com/pjreddie/darknet/master/cfg/yolov3.cfg').read_bytes())
print("Loading weights file (237MB). This might take a while…") print("Loading weights file (237MB). This might take a while…")
model.load_weights('https://github.com/shadiakiki1986/yolov3.weights/releases/download/3.0.1/yolov3.weights') model.load_weights('https://pjreddie.com/media/files/yolov3.weights')
if len(sys.argv) > 1: if len(sys.argv) > 1:
url = sys.argv[1] url = sys.argv[1]
else: else:
+11 -16
View File
@@ -1,16 +1,6 @@
import re, ctypes, sys, importlib import re, ctypes, sys
from tinygrad.runtime.support.am.amdev import AMDev, AMRegister from tinygrad.runtime.autogen.am import am, mp_11_0, mp_13_0_0, nbio_4_3_0, mmhub_3_0_0, gc_11_0_0, osssys_6_0_0
class AMDFake(AMDev):
def __init__(self, devfmt, vram, doorbell, mmio, dma_regions=None):
self.devfmt, self.vram, self.doorbell64, self.mmio, self.dma_regions = devfmt, vram, doorbell, mmio, dma_regions
self._run_discovery()
self._build_regs()
amdev = importlib.import_module("tinygrad.runtime.support.am.amdev")
amdev.AMDev = AMDFake
from tinygrad.runtime.ops_amd import PCIIface
def parse_amdgpu_logs(log_content, register_names=None): def parse_amdgpu_logs(log_content, register_names=None):
register_map = register_names register_map = register_names
@@ -33,11 +23,16 @@ def parse_amdgpu_logs(log_content, register_names=None):
return processed_log return processed_log
def main(): def main():
regs_offset = {13: {0: [3072, 37784576]}, 28: {0: [93184, 37754880], 1: [201327616, 201461760], 2: [209716224, 209850368], 3: [218104832, 218238976], 4: [226493440, 226627584], 5: [234882048, 235016192], 6: [243270656, 243404800]}, 21: {0: [28672, 12582912, 37795840, 130023424, 306184192], 1: [201326592, 201463808, 201465856, 204210176, 204472320], 2: [209715200, 209852416, 209854464, 212598784, 212860928], 3: [218103808, 218241024, 218243072, 220987392, 221249536], 4: [226492416, 226629632, 226631680, 229376000, 229638144], 5: [234881024, 235018240, 235020288, 237764608, 238026752], 6: [243269632, 243406848, 243408896, 246153216, 246415360]}, 22: {0: [18, 192, 13504, 36864, 37764096]}, 1: {0: [4704, 40960, 114688, 37760000]}, 2: {0: [3872, 37790720]}, 11: {0: [70656, 38103040]}, 12: {0: [106496, 37783552]}, 15: {0: [90112, 14417920, 14680064, 14942208, 38009856]}, 16: {0: [90112, 14417920, 14680064, 14942208, 38009856]}, 14: {0: [0, 20, 3360, 66560, 37859328, 67371008]}, 26: {0: [0, 20, 3360, 66560, 37859328, 67371008]}, 23: {0: [4256, 37789696]}, 33: {0: [0, 20, 3360, 66560, 37859328, 67371008]}, 25: {0: []}, 3: {0: [4704, 40960, 114688, 37760000]}, 4: {0: [4704, 40960, 114688, 37760000]}, 24: {0: [92160, 92672, 37752832, 54788096]}, 27: {0: [91648, 37751808], 1: [201339904, 201458176], 2: [209728512, 209846784], 3: [218117120, 218235392], 4: [226505728, 226624000], 5: [234894336, 235012608], 6: [243282944, 243401216]}, 29: {0: [201342976, 201344000, 205520896, 205537280], 1: [209731584, 209732608, 213909504, 213925888], 2: [218120192, 218121216, 222298112, 222314496], 3: [226508800, 226509824, 230686720, 230703104], 4: [234897408, 234898432, 239075328, 239091712], 5: [243286016, 243287040, 247463936, 247480320]}, 17: {0: [30720, 32256], 1: [31488, 73728]}}
reg_names = {} reg_names = {}
dev = PCIIface(None, 0) def _prepare_registers(modules):
for x, y in dev.dev_impl.__dict__.items(): for base, m in modules:
if isinstance(y, AMRegister): for k, regval in m.__dict__.items():
for inst, addr in y.addr.keys(): reg_names[addr] = f"{x}, xcc={inst}" if k.startswith("reg") and not k.endswith("_BASE_IDX") and (base_idx:=getattr(m, f"{k}_BASE_IDX", None)) is not None:
reg_names[regs_offset[am.__dict__.get(f"{base}_HWIP")][0][base_idx] + regval] = k
_prepare_registers([("MP0", mp_13_0_0), ("NBIO", nbio_4_3_0), ("MMHUB", mmhub_3_0_0), ("GC", gc_11_0_0), ("OSSSYS", osssys_6_0_0)])
with open(sys.argv[1], 'r') as f: with open(sys.argv[1], 'r') as f:
log_content = log_content_them = f.read() log_content = log_content_them = f.read()
+1 -1
View File
@@ -1,5 +1,5 @@
from typing import Tuple, List, NamedTuple, Any, Dict, Optional, Union, DefaultDict, cast from typing import Tuple, List, NamedTuple, Any, Dict, Optional, Union, DefaultDict, cast
from tinygrad.codegen.opt.kernel import Ops, MemOp, UOp from tinygrad.opt.kernel import Ops, MemOp, UOp
from tinygrad.uop.ops import BinaryOps, UnaryOps from tinygrad.uop.ops import BinaryOps, UnaryOps
from tinygrad.dtype import DType, dtypes from tinygrad.dtype import DType, dtypes
from tinygrad.helpers import DEBUG from tinygrad.helpers import DEBUG
+1 -1
View File
@@ -3,7 +3,7 @@ from platform import system
from typing import Tuple, Dict, List, Optional from typing import Tuple, Dict, List, Optional
from tinygrad import dtypes from tinygrad import dtypes
from tinygrad.uop.ops import BinaryOps, UnaryOps, TernaryOps from tinygrad.uop.ops import BinaryOps, UnaryOps, TernaryOps
from tinygrad.codegen.opt.kernel import Ops, UOp from tinygrad.opt.kernel import Ops, UOp
from tinygrad.helpers import CI from tinygrad.helpers import CI
from tinygrad.codegen.assembly import uops_to_asmstyle, AssemblyLanguage from tinygrad.codegen.assembly import uops_to_asmstyle, AssemblyLanguage
+1 -1
View File
@@ -1,7 +1,7 @@
from typing import List from typing import List
import struct import struct
from tinygrad.codegen.assembly import uops_to_asmstyle, AssemblyLanguage from tinygrad.codegen.assembly import uops_to_asmstyle, AssemblyLanguage
from tinygrad.codegen.opt.kernel import Ops, UOp from tinygrad.opt.kernel import Ops, UOp
from tinygrad import dtypes from tinygrad import dtypes
from tinygrad.uop.ops import BinaryOps, UnaryOps, TernaryOps from tinygrad.uop.ops import BinaryOps, UnaryOps, TernaryOps
from tinygrad.runtime.ops_cuda import arch from tinygrad.runtime.ops_cuda import arch
+1 -1
View File
@@ -2,7 +2,7 @@ import yaml
from typing import Tuple, Set, Dict from typing import Tuple, Set, Dict
from tinygrad import dtypes from tinygrad import dtypes
from tinygrad.codegen.assembly import AssemblyCodegen, Register from tinygrad.codegen.assembly import AssemblyCodegen, Register
from tinygrad.codegen.opt.kernel import Ops from tinygrad.opt.kernel import Ops
from tinygrad.uop.ops import BinaryOps, UnaryOps, TernaryOps from tinygrad.uop.ops import BinaryOps, UnaryOps, TernaryOps
from tinygrad.runtime.ops_gpu import ROCM_LLVM_PATH from tinygrad.runtime.ops_gpu import ROCM_LLVM_PATH
+1 -1
View File
@@ -2,7 +2,7 @@ from typing import Dict, List, Final, Callable, DefaultDict
from collections import defaultdict from collections import defaultdict
from tinygrad.uop.ops import UnaryOps, BinaryOps, TernaryOps, Op from tinygrad.uop.ops import UnaryOps, BinaryOps, TernaryOps, Op
from tinygrad.helpers import DType, PtrDType, dtypes, ImageDType, DEBUG, getenv from tinygrad.helpers import DType, PtrDType, dtypes, ImageDType, DEBUG, getenv
from tinygrad.codegen.opt.kernel import UOp, Ops from tinygrad.opt.kernel import UOp, Ops
from triton.compiler import compile as triton_compile from triton.compiler import compile as triton_compile
import linecache import linecache
import math import math
+2 -2
View File
@@ -2,11 +2,11 @@ from tinygrad import Tensor, Device, Context, GlobalCounters, dtypes
from tinygrad.uop.ops import UOp, Ops, KernelInfo, graph_rewrite, AxisType, PatternMatcher, UPat from tinygrad.uop.ops import UOp, Ops, KernelInfo, graph_rewrite, AxisType, PatternMatcher, UPat
from tinygrad.engine.realize import CompiledRunner, ExecItem, get_program from tinygrad.engine.realize import CompiledRunner, ExecItem, get_program
from tinygrad.dtype import AddrSpace from tinygrad.dtype import AddrSpace
from tinygrad.schedule.kernelize import merge_views, view_left
from tinygrad.helpers import getenv, colored, prod, unwrap from tinygrad.helpers import getenv, colored, prod, unwrap
from tinygrad.shape.shapetracker import ShapeTracker, View from tinygrad.shape.shapetracker import ShapeTracker, View
from tinygrad.shape.view import strides_for_shape from tinygrad.shape.view import strides_for_shape
from tinygrad.codegen.opt.kernel import axis_colors from tinygrad.opt.kernel import axis_colors
from tinygrad.codegen.opt.swizzler import merge_views, view_left
def to_colored(full_shape, axis_types): return '_'.join([colored(str(s), axis_colors[at]) for s,at in zip(full_shape, axis_types)]) def to_colored(full_shape, axis_types): return '_'.join([colored(str(s), axis_colors[at]) for s,at in zip(full_shape, axis_types)])
+2 -2
View File
@@ -5,9 +5,9 @@ from typing import Optional, List, Tuple, cast, Dict, Final, DefaultDict, Self
from tinygrad.engine.realize import get_program from tinygrad.engine.realize import get_program
# for copied uops # for copied uops
from tinygrad.codegen.opt.kernel import Kernel, KernelOptError from tinygrad.opt.kernel import Kernel, KernelOptError
from tinygrad.uop.ops import UOp, Ops, BinaryOps, UnaryOps, TernaryOps, KernelInfo from tinygrad.uop.ops import UOp, Ops, BinaryOps, UnaryOps, TernaryOps, KernelInfo
from tinygrad.codegen.opt.search import Opt, OptOps from tinygrad.opt.search import Opt, OptOps
from tinygrad import Device, dtypes, Tensor from tinygrad import Device, dtypes, Tensor
from tinygrad.dtype import PtrDType, DType, DTYPES_DICT from tinygrad.dtype import PtrDType, DType, DTYPES_DICT
from tinygrad.shape.shapetracker import ShapeTracker from tinygrad.shape.shapetracker import ShapeTracker
+1 -1
View File
@@ -2,7 +2,7 @@ import numpy as np
from tinygrad import dtypes, Tensor from tinygrad import dtypes, Tensor
from tinygrad.helpers import getenv, get_single_element from tinygrad.helpers import getenv, get_single_element
from tinygrad.dtype import _to_np_dtype from tinygrad.dtype import _to_np_dtype
from tinygrad.codegen.opt.kernel import OptOps from tinygrad.opt.kernel import OptOps
from tinygrad.engine.realize import lower_schedule from tinygrad.engine.realize import lower_schedule
dtype_in = dtypes.half if getenv("HALF") else dtypes.bfloat16 if getenv("BFLOAT16") else dtypes.float dtype_in = dtypes.half if getenv("HALF") else dtypes.bfloat16 if getenv("BFLOAT16") else dtypes.float
+1 -1
View File
@@ -1,6 +1,6 @@
from tinygrad import Tensor, dtypes, Device from tinygrad import Tensor, dtypes, Device
from tinygrad.helpers import getenv, DEBUG from tinygrad.helpers import getenv, DEBUG
from tinygrad.codegen.opt.kernel import Kernel, Opt, OptOps from tinygrad.opt.kernel import Kernel, Opt, OptOps
from tinygrad.engine.realize import CompiledRunner, ExecItem, get_program from tinygrad.engine.realize import CompiledRunner, ExecItem, get_program
from dataclasses import replace from dataclasses import replace
+1 -1
View File
@@ -37,7 +37,7 @@ B = Tensor.rand(K, N, device="CPU")
C = (A.reshape(M, 1, K) * B.permute(1,0).reshape(1, N, K)).sum(axis=2) C = (A.reshape(M, 1, K) * B.permute(1,0).reshape(1, N, K)).sum(axis=2)
sched = C.schedule() sched = C.schedule()
from tinygrad.codegen.opt.kernel import Kernel from tinygrad.opt.kernel import Kernel
from tinygrad.device import CompilerOptions from tinygrad.device import CompilerOptions
lin = Kernel(sched[-1].ast, CompilerOptions(has_local=False, supports_float4=False)) lin = Kernel(sched[-1].ast, CompilerOptions(has_local=False, supports_float4=False))
lin.to_program() lin.to_program()
+1
View File
@@ -8,6 +8,7 @@ bert_train_params = {
"BS": 96, "BS": 96,
"EVAL_BS": 96, "EVAL_BS": 96,
"FUSE_ARANGE": 1, "FUSE_ARANGE": 1,
"FUSE_ARANGE_UINT": 0,
"BASEDIR": "/raid/datasets/wiki", "BASEDIR": "/raid/datasets/wiki",
} }
-61
View File
@@ -1,61 +0,0 @@
# HuggingFace ONNX
Tool for discovering, downloading, and validating ONNX models from HuggingFace.
## Extra Dependencies
```bash
pip install huggingface_hub pyyaml requests onnx onnxruntime numpy
```
## Huggingface Manager (discovering and downloading)
The `huggingface_manager.py` script discovers top ONNX models from HuggingFace, collects metadata, and optionally downloads them.
```bash
# Download top 50 models sorted by downloads
python huggingface_manager.py --limit 50 --download
# Just collect metadata (no download)
python huggingface_manager.py --limit 100
# Sort by likes instead of downloads
python huggingface_manager.py --limit 20 --sort likes --download
# Custom output file
python huggingface_manager.py --limit 10 --output my_models.yaml
```
### Output Format
The tool generates a YAML file with the following structure:
```yaml
repositories:
"model-name":
url: "https://huggingface.co/model-name"
download_path: "/path/to/models/..." # when --download used
files:
- file: "model.onnx"
size: "90.91MB"
total_size: "2.45GB"
created_at: "2024-01-15T10:30:00Z"
```
## Run Models (validation)
The `run_models.py` script validates ONNX models against ONNX Runtime for correctness.
```bash
# Validate models from a YAML configuration file
python run_models.py --validate huggingface_repos.yaml
# Debug specific repository (downloads and validates all ONNX models)
python run_models.py --debug sentence-transformers/all-MiniLM-L6-v2
# Debug specific model file
python run_models.py --debug sentence-transformers/all-MiniLM-L6-v2/onnx/model.onnx
# Debug with model truncation for debugging and validating intermediate results
DEBUGONNX=1 python run_models.py --debug sentence-transformers/all-MiniLM-L6-v2/onnx/model.onnx --truncate 10
```
@@ -0,0 +1,85 @@
import yaml, time, requests, argparse
from pathlib import Path
from huggingface_hub import list_models, HfApi
from tinygrad.helpers import tqdm
HUGGINGFACE_URL = "https://huggingface.co"
SKIPPED_FILES = [
"fp16", "int8", "uint8", "quantized", # numerical accuracy issues
"avx2", "arm64", "avx512", "avx512_vnni", # numerical accuracy issues
"q4", "q4f16", "bnb4", # unimplemented quantization
"model_O4", # requires non cpu ort runner and MemcpyFromHost op
"merged", # TODO implement attribute with graph type and Loop op
]
SKIPPED_REPO_PATHS = [
# Invalid model-index
"AdamCodd/vit-base-nsfw-detector",
# TODO: implement attribute with graph type and Loop op
"minishlab/potion-base-8M", "minishlab/M2V_base_output", "minishlab/potion-retrieval-32M",
# TODO: implement SimplifiedLayerNormalization, SkipSimplifiedLayerNormalization, GroupQueryAttention
"HuggingFaceTB/SmolLM2-360M-Instruct",
# TODO: implement SimplifiedLayerNormalization, SkipSimplifiedLayerNormalization, RotaryEmbedding, MultiHeadAttention
"HuggingFaceTB/SmolLM2-1.7B-Instruct",
# TODO: implmement RandomNormalLike
"stabilityai/stable-diffusion-xl-base-1.0", "stabilityai/sdxl-turbo", 'SimianLuo/LCM_Dreamshaper_v7',
# TODO: implement NonZero
"mangoapps/fb_zeroshot_mnli_onnx",
# TODO huge Concat in here with 1024 (1, 3, 32, 32) Tensors, and maybe a MOD bug with const folding
"briaai/RMBG-2.0",
]
def get_top_repos(n: int, sort: str) -> list[str]: # list["FacebookAI/xlm-roberta-large", ...]
print(f"** Getting top {n} models sorted by {sort} **")
repos = []
i = 0
for model in list_models(filter="onnx", sort=sort):
if model.id in SKIPPED_REPO_PATHS: continue
print(f"{i+1}/{n}: {model.id} ({getattr(model, sort)})")
repos.append(model.id)
i += 1
if i == n: break
return repos
def get_metadata(repos:list[str]) -> dict:
api = HfApi()
repos_metadata = {"repositories": {}}
total_size = 0
# TODO: speed head requests up with async?
for repo in tqdm(repos, desc="Getting metadata"):
files_metadata = []
model_info = api.model_info(repo)
for file in model_info.siblings:
filename = file.rfilename
if not (filename.endswith('.onnx') or filename.endswith('.onnx_data')): continue
if any(skip_str in filename for skip_str in SKIPPED_FILES): continue
head = requests.head(f"{HUGGINGFACE_URL}/{repo}/resolve/main/{filename}", allow_redirects=True)
file_size = file.size or int(head.headers.get('Content-Length', 0))
files_metadata.append({"file": filename, "size": f"{file_size/1e6:.2f}MB"})
total_size += file_size
repos_metadata["repositories"][repo] = {
"url": f"{HUGGINGFACE_URL}/{repo}",
"download_path": None,
"files": files_metadata,
}
repos_metadata['total_size'] = f"{total_size/1e9:.2f}GB"
repos_metadata['created_at'] = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())
return repos_metadata
if __name__ == "__main__":
sort = "downloads" # recent 30 days downloads
huggingface_onnx_dir = Path(__file__).parent
parser = argparse.ArgumentParser(description="Produces a YAML file with metadata of top huggingface onnx models")
parser.add_argument("--limit", type=int, required=True, help="Number of top repositories to process (e.g., 100)")
parser.add_argument("--output", type=str, default="huggingface_repos.yaml", help="Output YAML file name to save the report")
args = parser.parse_args()
top_repos = get_top_repos(args.limit, sort)
metadata = get_metadata(top_repos)
yaml_path = huggingface_onnx_dir / args.output
with open(yaml_path, 'w') as f:
yaml.dump(metadata, f, sort_keys=False)
print(f"YAML saved to: {str(yaml_path)}")
+29
View File
@@ -0,0 +1,29 @@
import yaml, argparse
from pathlib import Path
from huggingface_hub import snapshot_download
def download_models(yaml_file: str, download_dir: str) -> None:
with open(yaml_file, 'r') as f: metadata = yaml.safe_load(f)
n = len(metadata["repositories"])
for i, (model_id, model_data) in enumerate(metadata["repositories"].items()):
print(f"Downloading {i+1}/{n}: {model_id}...")
allow_patterns = [file_info["file"] for file_info in model_data["files"]]
root_path = Path(snapshot_download(repo_id=model_id, allow_patterns=allow_patterns, cache_dir=download_dir))
# download configs too (the sizes are small)
snapshot_download(repo_id=model_id, allow_patterns=["*config.json"], cache_dir=download_dir)
print(f"Downloaded model files to: {root_path}")
model_data["download_path"] = str(root_path)
# Save the updated metadata back to the YAML file
with open(yaml_file, 'w') as f: yaml.dump(metadata, f, sort_keys=False)
print("Download completed according to YAML file.")
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Download models from Huggingface Hub based on a YAML configuration file.")
parser.add_argument("input", type=str, help="Path to the input YAML configuration file containing model information.")
args = parser.parse_args()
models_folder = Path(__file__).parent / "models"
models_folder.mkdir(parents=True, exist_ok=True)
download_models(args.input, str(models_folder))
@@ -1,230 +0,0 @@
import yaml
import time
import requests
import argparse
from pathlib import Path
from huggingface_hub import list_models, HfApi, snapshot_download
from tinygrad.helpers import _ensure_downloads_dir
DOWNLOADS_DIR = _ensure_downloads_dir() / "models"
from tinygrad.helpers import tqdm
def snapshot_download_with_retry(*, repo_id: str, allow_patterns: list[str]|tuple[str, ...]|None=None, cache_dir: str|Path|None=None,
tries: int=2, **kwargs) -> Path:
for attempt in range(tries):
try:
return Path(snapshot_download(
repo_id=repo_id,
allow_patterns=allow_patterns,
cache_dir=str(cache_dir) if cache_dir is not None else None,
**kwargs
))
except Exception as e:
if attempt == tries-1: raise
time.sleep(1)
# Constants for filtering models
HUGGINGFACE_URL = "https://huggingface.co"
SKIPPED_FILES = [
"fp16", "int8", "uint8", "quantized", # numerical accuracy issues
"avx2", "arm64", "avx512", "avx512_vnni", # numerical accuracy issues
"q4", "q4f16", "bnb4", # unimplemented quantization
"model_O4", # requires non cpu ort runner and MemcpyFromHost op
"merged", # TODO implement attribute with graph type and Loop op
]
SKIPPED_REPO_PATHS = [
# Invalid model-index
"AdamCodd/vit-base-nsfw-detector",
# TODO: implement attribute with graph type and Loop op
"minishlab/potion-base-8M", "minishlab/M2V_base_output", "minishlab/potion-retrieval-32M",
# TODO: implement SimplifiedLayerNormalization, SkipSimplifiedLayerNormalization, GroupQueryAttention
"HuggingFaceTB/SmolLM2-360M-Instruct",
# TODO: implement SimplifiedLayerNormalization, SkipSimplifiedLayerNormalization, RotaryEmbedding, MultiHeadAttention
"HuggingFaceTB/SmolLM2-1.7B-Instruct",
# TODO: implement RandomNormalLike
"stabilityai/stable-diffusion-xl-base-1.0", "stabilityai/sdxl-turbo", 'SimianLuo/LCM_Dreamshaper_v7',
# TODO: implement NonZero
"mangoapps/fb_zeroshot_mnli_onnx",
# TODO huge Concat in here with 1024 (1, 3, 32, 32) Tensors, and maybe a MOD bug with const folding
"briaai/RMBG-2.0",
]
class HuggingFaceONNXManager:
def __init__(self):
self.base_dir = Path(__file__).parent
self.models_dir = DOWNLOADS_DIR
self.api = HfApi()
def discover_models(self, limit: int, sort: str = "downloads") -> list[str]:
print(f"Discovering top {limit} ONNX models sorted by {sort}...")
repos = []
i = 0
for model in list_models(filter="onnx", sort=sort):
if model.id in SKIPPED_REPO_PATHS:
continue
print(f" {i+1}/{limit}: {model.id} ({getattr(model, sort)})")
repos.append(model.id)
i += 1
if i == limit:
break
print(f"Found {len(repos)} suitable ONNX models")
return repos
def collect_metadata(self, repos: list[str]) -> dict:
print(f"Collecting metadata for {len(repos)} repositories...")
metadata = {"repositories": {}}
total_size = 0
for repo in tqdm(repos, desc="Collecting metadata"):
try:
files_metadata = []
model_info = self.api.model_info(repo)
for file in model_info.siblings:
filename = file.rfilename
if not (filename.endswith('.onnx') or filename.endswith('.onnx_data')):
continue
if any(skip_str in filename for skip_str in SKIPPED_FILES):
continue
# Get file size from API or HEAD request
try:
head = requests.head(
f"{HUGGINGFACE_URL}/{repo}/resolve/main/{filename}",
allow_redirects=True,
timeout=10
)
file_size = file.size or int(head.headers.get('Content-Length', 0))
except requests.RequestException:
file_size = file.size or 0
files_metadata.append({
"file": filename,
"size": f"{file_size/1e6:.2f}MB"
})
total_size += file_size
if files_metadata: # Only add repos with valid ONNX files
metadata["repositories"][repo] = {
"url": f"{HUGGINGFACE_URL}/{repo}",
"download_path": None,
"files": files_metadata,
}
except Exception as e:
print(f"WARNING: Failed to collect metadata for {repo}: {e}")
continue
metadata['total_size'] = f"{total_size/1e9:.2f}GB"
metadata['created_at'] = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())
print(f"Collected metadata for {len(metadata['repositories'])} repositories")
print(f"Total estimated download size: {metadata['total_size']}")
return metadata
def download_models(self, metadata: dict) -> dict:
self.models_dir.mkdir(parents=True, exist_ok=True)
repos = metadata["repositories"]
n = len(repos)
print(f"Downloading {n} repositories to {self.models_dir}...")
for i, (model_id, model_data) in enumerate(repos.items()):
print(f" Downloading {i+1}/{n}: {model_id}...")
try:
# Download ONNX model files
allow_patterns = [file_info["file"] for file_info in model_data["files"]]
root_path = snapshot_download_with_retry(
repo_id=model_id,
allow_patterns=allow_patterns,
cache_dir=str(self.models_dir)
)
# Download config files (usually small)
snapshot_download_with_retry(
repo_id=model_id,
allow_patterns=["*config.json"],
cache_dir=str(self.models_dir)
)
model_data["download_path"] = str(root_path)
print(f" Downloaded to: {root_path}")
except Exception as e:
print(f" ERROR: Failed to download {model_id}: {e}")
model_data["download_path"] = None
continue
successful_downloads = sum(1 for repo in repos.values() if repo["download_path"] is not None)
print(f"Successfully downloaded {successful_downloads}/{n} repositories")
print(f"All models saved to: {self.models_dir}")
return metadata
def save_metadata(self, metadata: dict, output_file: str):
yaml_path = self.base_dir / output_file
with open(yaml_path, 'w') as f:
yaml.dump(metadata, f, sort_keys=False)
print(f"Metadata saved to: {yaml_path}")
def discover_and_download(self, limit: int, output_file: str = "huggingface_repos.yaml",
sort: str = "downloads", download: bool = True):
print(f"Starting HuggingFace ONNX workflow...")
print(f" Limit: {limit} models")
print(f" Sort by: {sort}")
print(f" Download: {'Yes' if download else 'No'}")
print(f" Output: {output_file}")
print("-" * 50)
repos = self.discover_models(limit, sort)
metadata = self.collect_metadata(repos)
if download:
metadata = self.download_models(metadata)
self.save_metadata(metadata, output_file)
print("-" * 50)
print("Workflow completed successfully!")
if download:
successful = sum(1 for repo in metadata["repositories"].values()
if repo["download_path"] is not None)
print(f"{successful}/{len(metadata['repositories'])} models downloaded")
return metadata
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="HuggingFace ONNX Model Manager - Discover, collect metadata, and download ONNX models",
)
parser.add_argument("--limit", type=int, help="Number of top repositories to process")
parser.add_argument("--output", type=str, default="huggingface_repos.yaml",
help="Output YAML file name (default: huggingface_repos.yaml)")
parser.add_argument("--sort", type=str, default="downloads",
choices=["downloads", "likes", "created", "modified"],
help="Sort criteria for model discovery (default: downloads)")
parser.add_argument("--download", action="store_true", default=False,
help="Download models after collecting metadata")
args = parser.parse_args()
if not args.limit: parser.error("--limit is required")
manager = HuggingFaceONNXManager()
manager.discover_and_download(
limit=args.limit,
output_file=args.output,
sort=args.sort,
download=args.download
)
+50 -23
View File
@@ -1,11 +1,10 @@
import onnx, yaml, tempfile, time, argparse, json import onnx, yaml, tempfile, time, collections, pprint, argparse, json
from pathlib import Path from pathlib import Path
from typing import Any
from tinygrad.frontend.onnx import OnnxRunner from tinygrad.frontend.onnx import OnnxRunner
from extra.onnx import get_onnx_ops
from extra.onnx_helpers import validate, get_example_inputs from extra.onnx_helpers import validate, get_example_inputs
from extra.huggingface_onnx.huggingface_manager import DOWNLOADS_DIR, snapshot_download_with_retry
def get_config(root_path: Path) -> dict[str, Any]: def get_config(root_path: Path):
ret = {} ret = {}
for path in root_path.rglob("*config.json"): for path in root_path.rglob("*config.json"):
config = json.load(path.open()) config = json.load(path.open())
@@ -13,19 +12,19 @@ def get_config(root_path: Path) -> dict[str, Any]:
ret.update(config) ret.update(config)
return ret return ret
def get_tolerances(file_name: str) -> tuple[float, float]: def run_huggingface_validate(onnx_model_path, config, rtol, atol):
onnx_runner = OnnxRunner(onnx_model_path)
inputs = get_example_inputs(onnx_runner.graph_inputs, config)
validate(onnx_model_path, inputs, rtol=rtol, atol=atol)
def get_tolerances(file_name): # -> rtol, atol
# TODO very high rtol atol # TODO very high rtol atol
if "fp16" in file_name: return 9e-2, 9e-2 if "fp16" in file_name: return 9e-2, 9e-2
if any(q in file_name for q in ["int8", "uint8", "quantized"]): return 4, 4 if any(q in file_name for q in ["int8", "uint8", "quantized"]): return 4, 4
return 4e-3, 3e-2 return 4e-3, 3e-2
def run_huggingface_validate(onnx_model_path: str | Path, config: dict[str, Any], rtol: float, atol: float):
onnx_runner = OnnxRunner(onnx_model_path)
inputs = get_example_inputs(onnx_runner.graph_inputs, config)
validate(onnx_model_path, inputs, rtol=rtol, atol=atol)
def validate_repos(models:dict[str, tuple[Path, Path]]): def validate_repos(models:dict[str, tuple[Path, Path]]):
print(f"** Validating {len(models)} models **") print(f"** Validating {len(model_paths)} models **")
for model_id, (root_path, relative_path) in models.items(): for model_id, (root_path, relative_path) in models.items():
print(f"validating model {model_id}") print(f"validating model {model_id}")
model_path = root_path / relative_path model_path = root_path / relative_path
@@ -37,6 +36,25 @@ def validate_repos(models:dict[str, tuple[Path, Path]]):
et = time.time() - st et = time.time() - st
print(f"passed, took {et:.2f}s") print(f"passed, took {et:.2f}s")
def retrieve_op_stats(models:dict[str, tuple[Path, Path]]) -> dict:
ret = {}
op_counter = collections.Counter()
unsupported_ops = collections.defaultdict(set)
supported_ops = get_onnx_ops()
print(f"** Retrieving stats from {len(model_paths)} models **")
for model_id, (root_path, relative_path) in models.items():
print(f"examining {model_id}")
model_path = root_path / relative_path
onnx_runner = OnnxRunner(model_path)
for node in onnx_runner.graph_nodes:
op_counter[node.op] += 1
if node.op not in supported_ops:
unsupported_ops[node.op].add(model_id)
del onnx_runner
ret["unsupported_ops"] = {k:list(v) for k, v in unsupported_ops.items()}
ret["op_counter"] = op_counter.most_common()
return ret
def debug_run(model_path, truncate, config, rtol, atol): def debug_run(model_path, truncate, config, rtol, atol):
if truncate != -1: if truncate != -1:
model = onnx.load(model_path) model = onnx.load(model_path)
@@ -53,9 +71,12 @@ def debug_run(model_path, truncate, config, rtol, atol):
run_huggingface_validate(model_path, config, rtol, atol) run_huggingface_validate(model_path, config, rtol, atol)
if __name__ == "__main__": if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Huggingface ONNX Model Validator") parser = argparse.ArgumentParser(description="Huggingface ONNX Model Validator and Ops Checker")
parser.add_argument("--validate", type=str, default="", parser.add_argument("input", type=str, help="Path to the input YAML configuration file containing model information.")
help="Validate correctness of models from the specified YAML configuration file") parser.add_argument("--check_ops", action="store_true", default=False,
help="Check support for ONNX operations in models from the YAML file")
parser.add_argument("--validate", action="store_true", default=False,
help="Validate correctness of models from the YAML file")
parser.add_argument("--debug", type=str, default="", parser.add_argument("--debug", type=str, default="",
help="""Validates without explicitly needing a YAML or models pre-installed. help="""Validates without explicitly needing a YAML or models pre-installed.
provide repo id (e.g. "minishlab/potion-base-8M") to validate all onnx models inside the repo provide repo id (e.g. "minishlab/potion-base-8M") to validate all onnx models inside the repo
@@ -64,13 +85,13 @@ if __name__ == "__main__":
parser.add_argument("--truncate", type=int, default=-1, help="Truncate the ONNX model so intermediate results can be validated") parser.add_argument("--truncate", type=int, default=-1, help="Truncate the ONNX model so intermediate results can be validated")
args = parser.parse_args() args = parser.parse_args()
if not (args.validate or args.debug): if not (args.check_ops or args.validate or args.debug):
parser.error("Please provide either --validate <yaml_file> or --debug <repo_id>.") parser.error("Please provide either --validate, --check_ops, or --debug.")
if args.truncate != -1 and not args.debug: if args.truncate != -1 and not args.debug:
parser.error("--truncate and --debug should be used together for debugging") parser.error("--truncate and --debug should be used together for debugging")
if args.validate: if args.check_ops or args.validate:
with open(args.validate, 'r') as f: with open(args.input, 'r') as f:
data = yaml.safe_load(f) data = yaml.safe_load(f)
assert all(repo["download_path"] is not None for repo in data["repositories"].values()), "please run `download_models.py` for this yaml" assert all(repo["download_path"] is not None for repo in data["repositories"].values()), "please run `download_models.py` for this yaml"
model_paths = { model_paths = {
@@ -80,16 +101,22 @@ if __name__ == "__main__":
if model["file"].endswith(".onnx") if model["file"].endswith(".onnx")
} }
validate_repos(model_paths) if args.check_ops:
pprint.pprint(retrieve_op_stats(model_paths))
if args.validate:
validate_repos(model_paths)
if args.debug: if args.debug:
from huggingface_hub import snapshot_download
download_dir = Path(__file__).parent / "models"
path:list[str] = args.debug.split("/") path:list[str] = args.debug.split("/")
if len(path) == 2: if len(path) == 2:
# repo id # repo id
# validates all onnx models inside repo # validates all onnx models inside repo
repo_id = "/".join(path) repo_id = "/".join(path)
root_path = snapshot_download_with_retry(repo_id=repo_id, allow_patterns=["*.onnx", "*.onnx_data"], cache_dir=DOWNLOADS_DIR) root_path = Path(snapshot_download(repo_id=repo_id, allow_patterns=["*.onnx", "*.onnx_data"], cache_dir=download_dir))
snapshot_download_with_retry(repo_id=repo_id, allow_patterns=["*config.json"], cache_dir=DOWNLOADS_DIR) snapshot_download(repo_id=repo_id, allow_patterns=["*config.json"], cache_dir=download_dir)
config = get_config(root_path) config = get_config(root_path)
for onnx_model in root_path.rglob("*.onnx"): for onnx_model in root_path.rglob("*.onnx"):
rtol, atol = get_tolerances(onnx_model.name) rtol, atol = get_tolerances(onnx_model.name)
@@ -101,8 +128,8 @@ if __name__ == "__main__":
onnx_model = path[-1] onnx_model = path[-1]
assert path[-1].endswith(".onnx") assert path[-1].endswith(".onnx")
repo_id, relative_path = "/".join(path[:2]), "/".join(path[2:]) repo_id, relative_path = "/".join(path[:2]), "/".join(path[2:])
root_path = snapshot_download_with_retry(repo_id=repo_id, allow_patterns=[relative_path], cache_dir=DOWNLOADS_DIR) root_path = Path(snapshot_download(repo_id=repo_id, allow_patterns=[relative_path], cache_dir=download_dir))
snapshot_download_with_retry(repo_id=repo_id, allow_patterns=["*config.json"], cache_dir=DOWNLOADS_DIR) snapshot_download(repo_id=repo_id, allow_patterns=["*config.json"], cache_dir=download_dir)
config = get_config(root_path) config = get_config(root_path)
rtol, atol = get_tolerances(onnx_model) rtol, atol = get_tolerances(onnx_model)
print(f"validating {relative_path} with truncate={args.truncate}, {rtol=}, {atol=}") print(f"validating {relative_path} with truncate={args.truncate}, {rtol=}, {atol=}")
+2 -2
View File
@@ -4,9 +4,9 @@ import numpy as np
np.set_printoptions(suppress=True) np.set_printoptions(suppress=True)
import math, functools, time, random, statistics import math, functools, time, random, statistics
from tinygrad.helpers import DEBUG, getenv, CACHELEVEL, diskcache_get, diskcache_put, colored, Profiling from tinygrad.helpers import DEBUG, getenv, CACHELEVEL, diskcache_get, diskcache_put, colored, Profiling
from tinygrad.codegen.opt.kernel import Kernel from tinygrad.opt.kernel import Kernel
from tinygrad.device import Buffer, Device, CompileError from tinygrad.device import Buffer, Device, CompileError
from tinygrad.codegen.opt.search import _ensure_buffer_alloc, get_kernel_actions, _time_program from tinygrad.opt.search import _ensure_buffer_alloc, get_kernel_actions, _time_program
from tinygrad.engine.realize import get_program from tinygrad.engine.realize import get_program
class MCTSNode: class MCTSNode:
+4 -2
View File
@@ -181,11 +181,13 @@ class Transformer:
def forward(self, tokens:Tensor, start_pos:Union[Variable,int], temperature:float, top_k:int, top_p:float, alpha_f:float, alpha_p:float): def forward(self, tokens:Tensor, start_pos:Union[Variable,int], temperature:float, top_k:int, top_p:float, alpha_f:float, alpha_p:float):
_bsz, seqlen = tokens.shape _bsz, seqlen = tokens.shape
h = self.tok_embeddings(tokens) h = self.tok_embeddings(tokens)
freqs_cis = self.freqs_cis.cast(h.dtype)[:, start_pos:start_pos+seqlen, :, :, :]
self.freqs_cis = self.freqs_cis.cast(h.dtype).contiguous()
freqs_cis = self.freqs_cis[:, start_pos:start_pos+seqlen, :, :, :]
mask = Tensor.full((1, 1, seqlen, start_pos+seqlen), float("-inf"), dtype=h.dtype, device=h.device).triu(start_pos+1) if seqlen > 1 else None mask = Tensor.full((1, 1, seqlen, start_pos+seqlen), float("-inf"), dtype=h.dtype, device=h.device).triu(start_pos+1) if seqlen > 1 else None
for layer in self.layers: h = layer(h, start_pos, freqs_cis, mask) for layer in self.layers: h = layer(h, start_pos, freqs_cis, mask)
logits = self.output(self.norm(h)) logits = self.output(self.norm(h)).float()
if math.isnan(temperature): return logits if math.isnan(temperature): return logits
return sample(logits[:, -1, :].flatten(), temperature, top_k, top_p, alpha_f, alpha_p) return sample(logits[:, -1, :].flatten(), temperature, top_k, top_p, alpha_f, alpha_p)
+1155
View File
File diff suppressed because it is too large Load Diff
+2 -1
View File
@@ -1,6 +1,7 @@
from tinygrad import Tensor from tinygrad import Tensor
from tinygrad.tensor import _to_np_dtype from tinygrad.tensor import _to_np_dtype
from tinygrad.frontend.onnx import OnnxRunner, OnnxValue from tinygrad.frontend.onnx import OnnxRunner
from extra.onnx import OnnxValue
import numpy as np import numpy as np
import onnxruntime as ort import onnxruntime as ort
+3 -3
View File
@@ -5,9 +5,9 @@ from tinygrad.nn import Linear
from tinygrad.tensor import Tensor from tinygrad.tensor import Tensor
from tinygrad.nn.optim import Adam from tinygrad.nn.optim import Adam
from tinygrad.nn.state import get_parameters, get_state_dict, safe_save, safe_load, load_state_dict from tinygrad.nn.state import get_parameters, get_state_dict, safe_save, safe_load, load_state_dict
from tinygrad.codegen.opt.search import actions from tinygrad.opt.search import actions
from extra.optimization.helpers import load_worlds, ast_str_to_lin, lin_to_feats, assert_same_lin from extra.optimization.helpers import load_worlds, ast_str_to_lin, lin_to_feats, assert_same_lin
from tinygrad.codegen.opt.kernel import Kernel from tinygrad.opt.kernel import Kernel
from tinygrad.helpers import getenv from tinygrad.helpers import getenv
# stuff needed to unpack a kernel # stuff needed to unpack a kernel
@@ -17,7 +17,7 @@ from tinygrad.shape.shapetracker import ShapeTracker
from tinygrad.shape.view import View from tinygrad.shape.view import View
from tinygrad.uop.ops import Variable from tinygrad.uop.ops import Variable
inf, nan = float('inf'), float('nan') inf, nan = float('inf'), float('nan')
from tinygrad.codegen.opt.kernel import Opt, OptOps from tinygrad.opt.kernel import Opt, OptOps
INNER = 256 INNER = 256
class PolicyNet: class PolicyNet:
+3 -3
View File
@@ -10,11 +10,11 @@ from tinygrad.shape.shapetracker import ShapeTracker
from tinygrad.shape.view import View from tinygrad.shape.view import View
from tinygrad.uop.ops import Variable from tinygrad.uop.ops import Variable
inf, nan = float('inf'), float('nan') inf, nan = float('inf'), float('nan')
from tinygrad.codegen.opt.kernel import Opt, OptOps from tinygrad.opt.kernel import Opt, OptOps
# more stuff # more stuff
from tinygrad.codegen.opt.kernel import Kernel from tinygrad.opt.kernel import Kernel
from tinygrad.codegen.opt.search import actions from tinygrad.opt.search import actions
from extra.optimization.helpers import lin_to_feats from extra.optimization.helpers import lin_to_feats
from extra.optimization.pretrain_valuenet import ValueNet from extra.optimization.pretrain_valuenet import ValueNet
from tinygrad.nn.optim import Adam from tinygrad.nn.optim import Adam
+3 -3
View File
@@ -1,8 +1,8 @@
import random import random
from extra.optimization.helpers import load_worlds, ast_str_to_lin from extra.optimization.helpers import load_worlds, ast_str_to_lin
from tinygrad.codegen.opt.search import actions from tinygrad.opt.search import actions
from tinygrad.codegen.opt.kernel import Kernel from tinygrad.opt.kernel import Kernel
from tinygrad.codegen.opt.heuristic import hand_coded_optimizations from tinygrad.opt.heuristic import hand_coded_optimizations
from tinygrad.helpers import tqdm from tinygrad.helpers import tqdm
tactions = set() tactions = set()
+3 -3
View File
@@ -1,6 +1,6 @@
# stuff needed to unpack a kernel # stuff needed to unpack a kernel
from tinygrad import Variable from tinygrad import Variable
from tinygrad.codegen.opt.kernel import Opt, OptOps from tinygrad.opt.kernel import Opt, OptOps
from tinygrad.uop.ops import UOp, Ops, KernelInfo from tinygrad.uop.ops import UOp, Ops, KernelInfo
from tinygrad.dtype import dtypes, PtrDType from tinygrad.dtype import dtypes, PtrDType
from tinygrad.shape.shapetracker import ShapeTracker from tinygrad.shape.shapetracker import ShapeTracker
@@ -11,7 +11,7 @@ inf, nan = float('inf'), float('nan')
UOps = Ops UOps = Ops
# kernel unpacker # kernel unpacker
from tinygrad.codegen.opt.kernel import Kernel from tinygrad.opt.kernel import Kernel
def ast_str_to_ast(ast_str:str) -> UOp: return eval(ast_str) def ast_str_to_ast(ast_str:str) -> UOp: return eval(ast_str)
def ast_str_to_lin(ast_str:str, opts=None): return Kernel(ast_str_to_ast(ast_str), opts=opts) def ast_str_to_lin(ast_str:str, opts=None): return Kernel(ast_str_to_ast(ast_str), opts=opts)
def kern_str_to_lin(kern_str:str, opts=None): def kern_str_to_lin(kern_str:str, opts=None):
@@ -103,7 +103,7 @@ def lin_to_feats(lin:Kernel, use_sts=True):
return ret return ret
from tinygrad.device import Device, Buffer from tinygrad.device import Device, Buffer
from tinygrad.codegen.opt.search import _ensure_buffer_alloc, _time_program from tinygrad.opt.search import _ensure_buffer_alloc, _time_program
from tinygrad.helpers import to_function_name, CACHELEVEL, diskcache_get, diskcache_put from tinygrad.helpers import to_function_name, CACHELEVEL, diskcache_get, diskcache_put
def time_linearizer(lin:Kernel, rawbufs:list[Buffer], allow_test_size=True, max_global_size=65536, cnt=3, disable_cache=False, clear_l2=False) -> float: # noqa: E501 def time_linearizer(lin:Kernel, rawbufs:list[Buffer], allow_test_size=True, max_global_size=65536, cnt=3, disable_cache=False, clear_l2=False) -> float: # noqa: E501
+2 -2
View File
@@ -1,4 +1,4 @@
from tinygrad.codegen.opt.kernel import Kernel from tinygrad.opt.kernel import Kernel
from tqdm import tqdm, trange from tqdm import tqdm, trange
import math import math
import random import random
@@ -14,7 +14,7 @@ from tinygrad.shape.shapetracker import ShapeTracker
from tinygrad.shape.view import View from tinygrad.shape.view import View
from tinygrad.uop.ops import Variable from tinygrad.uop.ops import Variable
inf, nan = float('inf'), float('nan') inf, nan = float('inf'), float('nan')
from tinygrad.codegen.opt.kernel import Opt, OptOps from tinygrad.opt.kernel import Opt, OptOps
from extra.optimization.helpers import lin_to_feats, MAX_DIMS from extra.optimization.helpers import lin_to_feats, MAX_DIMS
+1 -1
View File
@@ -3,7 +3,7 @@ import numpy as np
import math, random import math, random
from tinygrad.tensor import Tensor from tinygrad.tensor import Tensor
from tinygrad.nn.state import get_parameters, get_state_dict, safe_save, safe_load, load_state_dict from tinygrad.nn.state import get_parameters, get_state_dict, safe_save, safe_load, load_state_dict
from tinygrad.codegen.opt.search import actions, bufs_from_lin, get_kernel_actions from tinygrad.opt.search import actions, bufs_from_lin, get_kernel_actions
from tinygrad.nn.optim import Adam from tinygrad.nn.optim import Adam
from extra.optimization.extract_policynet import PolicyNet from extra.optimization.extract_policynet import PolicyNet
from extra.optimization.helpers import load_worlds, ast_str_to_lin, lin_to_feats, time_linearizer from extra.optimization.helpers import load_worlds, ast_str_to_lin, lin_to_feats, time_linearizer
+2 -2
View File
@@ -1,6 +1,6 @@
from typing import List, Tuple from typing import List, Tuple
from tinygrad.codegen.opt.kernel import Kernel from tinygrad.opt.kernel import Kernel
from tinygrad.codegen.opt.search import get_kernel_actions, actions from tinygrad.opt.search import get_kernel_actions, actions
_net = None _net = None
def beam_q_estimate(beam:List[Tuple[Kernel, float]]) -> List[Tuple[Kernel, float]]: def beam_q_estimate(beam:List[Tuple[Kernel, float]]) -> List[Tuple[Kernel, float]]:
+2 -2
View File
@@ -4,8 +4,8 @@ from extra.optimization.helpers import ast_str_to_lin, time_linearizer
from tinygrad import dtypes from tinygrad import dtypes
from tinygrad.helpers import BEAM, getenv from tinygrad.helpers import BEAM, getenv
from tinygrad.device import Device, Compiled from tinygrad.device import Device, Compiled
from tinygrad.codegen.opt.kernel import Kernel from tinygrad.opt.kernel import Kernel
from tinygrad.codegen.opt.search import beam_search, bufs_from_lin from tinygrad.opt.search import beam_search, bufs_from_lin
if __name__ == '__main__': if __name__ == '__main__':
+2 -2
View File
@@ -6,8 +6,8 @@ from copy import deepcopy
from tinygrad.helpers import getenv, colored from tinygrad.helpers import getenv, colored
from tinygrad.tensor import Tensor from tinygrad.tensor import Tensor
from tinygrad.nn.state import get_parameters, get_state_dict, safe_save, safe_load, load_state_dict from tinygrad.nn.state import get_parameters, get_state_dict, safe_save, safe_load, load_state_dict
from tinygrad.codegen.opt.search import bufs_from_lin, actions, get_kernel_actions from tinygrad.opt.search import bufs_from_lin, actions, get_kernel_actions
from tinygrad.codegen.opt.heuristic import hand_coded_optimizations from tinygrad.opt.heuristic import hand_coded_optimizations
from extra.optimization.helpers import load_worlds, ast_str_to_lin, lin_to_feats, time_linearizer from extra.optimization.helpers import load_worlds, ast_str_to_lin, lin_to_feats, time_linearizer
from extra.optimization.extract_policynet import PolicyNet from extra.optimization.extract_policynet import PolicyNet
from extra.optimization.pretrain_valuenet import ValueNet from extra.optimization.pretrain_valuenet import ValueNet
+1 -1
View File
@@ -1,5 +1,5 @@
from extra.optimization.helpers import load_worlds, ast_str_to_lin, time_linearizer from extra.optimization.helpers import load_worlds, ast_str_to_lin, time_linearizer
from tinygrad.codegen.opt.search import bufs_from_lin, get_kernel_actions from tinygrad.opt.search import bufs_from_lin, get_kernel_actions
if __name__ == "__main__": if __name__ == "__main__":
ast_strs = load_worlds() ast_strs = load_worlds()
+2 -2
View File
@@ -6,8 +6,8 @@ from tinygrad.helpers import getenv, BEAM
from tinygrad.engine.jit import TinyJit from tinygrad.engine.jit import TinyJit
from tinygrad.engine.realize import CompiledRunner, ExecItem, ScheduleItem, lower_schedule_item, get_program from tinygrad.engine.realize import CompiledRunner, ExecItem, ScheduleItem, lower_schedule_item, get_program
from tinygrad.renderer import ProgramSpec from tinygrad.renderer import ProgramSpec
from tinygrad.codegen.opt.kernel import Kernel, Opt, OptOps from tinygrad.opt.kernel import Kernel, Opt, OptOps
from tinygrad.codegen.opt.heuristic import hand_coded_optimizations from tinygrad.opt.heuristic import hand_coded_optimizations
import numpy as np import numpy as np
def move_jit_captured_to_dev(captured, device="DSP"): def move_jit_captured_to_dev(captured, device="DSP"):
+3 -7
View File
@@ -223,18 +223,15 @@ def max_unpool2d(self:torch.Tensor, indices:torch.Tensor, output_size):
@torch.library.impl("aten::arange", "privateuseone") @torch.library.impl("aten::arange", "privateuseone")
def arange(end, dtype=None, device=None, pin_memory=None): def arange(end, dtype=None, device=None, pin_memory=None):
has_float = isinstance(end, float) return wrap(Tensor.arange(0, end, dtype=_from_torch_dtype(dtype or torch.get_default_dtype())))
return wrap(Tensor.arange(0, end, dtype=_from_torch_dtype(dtype or (torch.get_default_dtype() if has_float else torch.int64))))
@torch.library.impl("aten::arange.start", "privateuseone") @torch.library.impl("aten::arange.start", "privateuseone")
def arange_start(start, end, dtype=None, device=None, pin_memory=None): def arange_start(start, end, dtype=None, device=None, pin_memory=None):
has_float = any(isinstance(x, float) for x in (start, end)) return wrap(Tensor.arange(start, end, dtype=_from_torch_dtype(dtype or torch.get_default_dtype())))
return wrap(Tensor.arange(start, end, dtype=_from_torch_dtype(dtype or (torch.get_default_dtype() if has_float else torch.int64))))
@torch.library.impl("aten::arange.start_step", "privateuseone") @torch.library.impl("aten::arange.start_step", "privateuseone")
def arange_start_step(start, end, step, dtype=None, device=None, pin_memory=None): def arange_start_step(start, end, step, dtype=None, device=None, pin_memory=None):
has_float = any(isinstance(x, float) for x in (start, end, step)) return wrap(Tensor.arange(start, end, step, dtype=_from_torch_dtype(dtype or torch.get_default_dtype())))
return wrap(Tensor.arange(start, end, step, dtype=_from_torch_dtype(dtype or (torch.get_default_dtype() if has_float else torch.int64))))
@torch.library.impl("aten::convolution_overrideable", "privateuseone") @torch.library.impl("aten::convolution_overrideable", "privateuseone")
def convolution_overrideable(input, weight, bias, stride, padding, dilation, transposed, output_padding, groups): def convolution_overrideable(input, weight, bias, stride, padding, dilation, transposed, output_padding, groups):
@@ -371,7 +368,6 @@ from torch._decomp import get_decompositions
decomps = [ decomps = [
aten.native_batch_norm, aten.native_batch_norm_backward, aten.native_batch_norm, aten.native_batch_norm_backward,
aten.native_layer_norm_backward, aten.native_layer_norm_backward,
aten.linalg_cross,
aten.addmm, aten.addmm,
aten.addcmul, aten.addcmul,
aten.addcdiv, aten.addcdiv,
+1 -7
View File
@@ -135,7 +135,7 @@ class TestTorchBackend(unittest.TestCase):
print(c.cpu()) print(c.cpu())
def test_maxpool2d_backward(self): def test_maxpool2d_backward(self):
x = torch.arange(3*3, dtype=torch.float32, device=device).reshape(1, 1, 3, 3).requires_grad_(True) x = torch.arange(3*3, device=device).reshape(1, 1, 3, 3).requires_grad_(True)
torch.nn.functional.max_pool2d(x, kernel_size=2, stride=1).sum().backward() torch.nn.functional.max_pool2d(x, kernel_size=2, stride=1).sum().backward()
np.testing.assert_equal(x.grad.squeeze().cpu().numpy(), [[0, 0, 0], [0, 1, 1], [0, 1, 1]]) np.testing.assert_equal(x.grad.squeeze().cpu().numpy(), [[0, 0, 0], [0, 1, 1], [0, 1, 1]])
@@ -203,12 +203,6 @@ class TestTorchBackend(unittest.TestCase):
b = torch.linalg.det(a) b = torch.linalg.det(a)
np.testing.assert_equal(b.cpu().numpy(), 120.0) np.testing.assert_equal(b.cpu().numpy(), 120.0)
def test_linalg_cross(self):
a = torch.tensor([[1, 0, 0], [0, 1, 0]], dtype=torch.float32, device=device)
b = torch.tensor([[0, 0, 1]], dtype=torch.float32, device=device)
cross = torch.linalg.cross(a, b)
np.testing.assert_equal(cross.cpu().numpy(), np.array([[0, -1, 0], [1, 0, 0]], dtype=np.float32))
def test_scalar_assign(self): def test_scalar_assign(self):
a = torch.tensor([1, 2, 3], device=device) a = torch.tensor([1, 2, 3], device=device)
a[1] = 4 a[1] = 4
-75
View File
@@ -1,75 +0,0 @@
import torch
#credit to KellerJordan at https://github.com/KellerJordan/Muon/tree/master
#some changes: classic momentum instead of weighting gradient
#added ns_steps, ns_params, nesterov as hyperparams
def zeropower_via_newtonschulz5(G:torch.tensor, steps:int, params:tuple[int, ...]):
"""
Newton-Schulz iteration to compute the zeroth power / orthogonalization of G. We opt to use a
quintic iteration whose coefficients are selected to maximize the slope at zero. For the purpose
of minimizing steps, it turns out to be empirically effective to keep increasing the slope at
zero even beyond the point where the iteration no longer converges all the way to one everywhere
on the interval. This iteration therefore does not produce UV^T but rather something like US'V^T
where S' is diagonal with S_{ii}' ~ Uniform(0.5, 1.5), which turns out not to hurt model
performance at all relative to UV^T, where USV^T = G is the SVD.
"""
assert G.ndim >= 2 # batched Muon implementation by @scottjmaddox, and put into practice in the record by @YouJiacheng
a, b, c = params
X = G
if G.size(-2) > G.size(-1):
X = X.mT
# Ensure spectral norm is at most 1
X = X / (X.norm(dim=(-2, -1), keepdim=True) + 1e-7)
# Perform the NS iterations
for _ in range(steps):
A = X @ X.mT
B = b * A + c * A @ A # quintic computation strategy adapted from suggestion by @jxbz, @leloykun, and @YouJiacheng
X = a * X + B @ X
if G.size(-2) > G.size(-1):
X = X.mT
return X
def muon_update(grad, momentum, beta=0.95, ns_steps=5, ns_params=(3.4445, -4.7750, 2.0315), nesterov=True):
if beta:
momentum.mul_(beta).add_(grad)
update = grad.add(momentum,alpha=beta) if nesterov else momentum
else: update = grad
if update.ndim == 4: # for the case of conv filters
update = update.view(len(update), -1)
update = zeropower_via_newtonschulz5(update, steps=ns_steps, params=ns_params)
return update
class SingleDeviceMuon(torch.optim.Optimizer):
"""
Muon variant for usage in non-distributed settings.
"""
def __init__(self, params, lr=0.02, weight_decay=0.0, momentum=0.95, ns_steps=5, ns_params=(3.4445, -4.7750, 2.0315), nesterov=True):
defaults = dict(lr=lr, weight_decay=weight_decay, momentum=momentum, ns_steps=ns_steps, ns_params=ns_params, nesterov=nesterov)
super().__init__(params, defaults)
@torch.no_grad()
def step(self, closure=None):
loss = None
if closure is not None:
with torch.enable_grad():
loss = closure()
for group in self.param_groups:
for p in group["params"]:
if p.grad is None:
p.grad = torch.zeros_like(p) # Force synchronization
state = self.state[p]
if len(state) == 0:
state["momentum_buffer"] = torch.zeros_like(p)
update = muon_update(p.grad, state["momentum_buffer"], beta=group["momentum"], ns_steps=group["ns_steps"],
ns_params=group["ns_params"], nesterov=group["nesterov"])
p.mul_(1.0 - group["lr"] * group["weight_decay"])
p.add_(update.reshape(p.shape), alpha=-group["lr"])
return loss
-2
View File
@@ -1,2 +0,0 @@
[pytest]
norecursedirs = extra
+5 -23
View File
@@ -18,34 +18,16 @@ testing_minimal = [
] ]
setup(name='tinygrad', setup(name='tinygrad',
version='0.11.0', version='0.10.3',
description='You like pytorch? You like micrograd? You love tinygrad! <3', description='You like pytorch? You like micrograd? You love tinygrad! <3',
author='George Hotz', author='George Hotz',
license='MIT', license='MIT',
long_description=long_description, long_description=long_description,
long_description_content_type='text/markdown', long_description_content_type='text/markdown',
packages = [ packages = ['tinygrad', 'tinygrad.runtime.autogen', 'tinygrad.runtime.autogen.am', 'tinygrad.codegen', 'tinygrad.nn',
'tinygrad', 'tinygrad.renderer', 'tinygrad.engine', 'tinygrad.viz', 'tinygrad.runtime', 'tinygrad.runtime.support', 'tinygrad.schedule',
'tinygrad.apps', 'tinygrad.runtime.support.am', 'tinygrad.runtime.graph', 'tinygrad.shape', 'tinygrad.uop', 'tinygrad.opt',
'tinygrad.codegen', 'tinygrad.runtime.support.nv', 'tinygrad.apps'],
'tinygrad.codegen.opt',
'tinygrad.engine',
'tinygrad.frontend',
'tinygrad.nn',
'tinygrad.renderer',
'tinygrad.runtime',
'tinygrad.runtime.autogen',
'tinygrad.runtime.autogen.am',
'tinygrad.runtime.autogen.nv',
'tinygrad.runtime.graph',
'tinygrad.runtime.support',
'tinygrad.runtime.support.am',
'tinygrad.runtime.support.nv',
'tinygrad.schedule',
'tinygrad.shape',
'tinygrad.uop',
'tinygrad.viz',
],
package_data = {'tinygrad': ['py.typed'], 'tinygrad.viz': ['index.html', 'assets/**/*', 'js/*']}, package_data = {'tinygrad': ['py.typed'], 'tinygrad.viz': ['index.html', 'assets/**/*', 'js/*']},
classifiers=[ classifiers=[
"Programming Language :: Python :: 3", "Programming Language :: Python :: 3",
+2 -2
View File
@@ -1,7 +1,7 @@
import random import random
from tinygrad.helpers import getenv from tinygrad.helpers import getenv
from tinygrad.codegen.opt.search import beam_search, bufs_from_lin from tinygrad.opt.search import beam_search, bufs_from_lin
from tinygrad.codegen.opt.heuristic import hand_coded_optimizations from tinygrad.opt.heuristic import hand_coded_optimizations
from extra.optimization.helpers import load_worlds, ast_str_to_lin, time_linearizer from extra.optimization.helpers import load_worlds, ast_str_to_lin, time_linearizer
def optimize_kernel(k): def optimize_kernel(k):
+1 -1
View File
@@ -2,7 +2,7 @@ import time
from tinygrad import Tensor, TinyJit, Device, Context from tinygrad import Tensor, TinyJit, Device, Context
from tinygrad.helpers import Profiling, Timing, GlobalCounters from tinygrad.helpers import Profiling, Timing, GlobalCounters
# python3 test/speed/external_test_speed_v_torch.py TestSpeed.test_add_a # python3 test/test_speed_v_torch.py TestSpeed.test_add_a
@TinyJit @TinyJit
def plus(a:Tensor, b:Tensor): return a+b def plus(a:Tensor, b:Tensor): return a+b
+22 -5
View File
@@ -1,8 +1,12 @@
from typing import List
from extra.models.resnet import ResNet50 from extra.models.resnet import ResNet50
from tinygrad import Tensor, nn, Device from tinygrad import Tensor, nn
from tinygrad.helpers import Profiling, Timing, getenv from tinygrad.helpers import Profiling, Timing, getenv, BEAM, NOOPT, DEBUG, Context, ansilen
from tinygrad.uop.ops import Ops from tinygrad.uop.ops import Ops
from tinygrad.opt.kernel import Kernel
from tinygrad.opt.heuristic import hand_coded_optimizations
from tinygrad.codegen import get_rewrites_for_renderer, apply_rewrites, rewrites_for_linearizer from tinygrad.codegen import get_rewrites_for_renderer, apply_rewrites, rewrites_for_linearizer
from tinygrad.opt.search import beam_search, bufs_from_lin
from tinygrad.uop.spec import type_verify from tinygrad.uop.spec import type_verify
if __name__ == "__main__": if __name__ == "__main__":
@@ -27,13 +31,26 @@ if __name__ == "__main__":
if not SCHEDULE_ONLY: if not SCHEDULE_ONLY:
asts = list({x.ast.key:x.ast for x in sched if x.ast.op is Ops.SINK}.values()) asts = list({x.ast.key:x.ast for x in sched if x.ast.op is Ops.SINK}.values())
if (restrict_kernel := getenv("RESTRICT_KERNEL", -1)) != -1: asts = asts[restrict_kernel:restrict_kernel+1] if (restrict_kernel := getenv("RESTRICT_KERNEL", -1)) != -1: asts = asts[restrict_kernel:restrict_kernel+1]
kernels: List[Kernel] = []
with Timing(f"***** model opts({len(asts):2d}) in "):
with Profiling(PROFILE >= 3):
for ast in asts:
k = Kernel(ast)
if BEAM:
with Context(DEBUG=max(2, DEBUG.value)): k = beam_search(k, bufs_from_lin(k), BEAM.value)
elif NOOPT: pass
else: k.apply_opts(hand_coded_optimizations(k))
kernels.append(k)
with Timing("***** model prep in "):
kernels = [(k, k.get_optimized_ast(), get_rewrites_for_renderer(k.opts, linearizer=False)) for k in kernels]
rewrites = get_rewrites_for_renderer(Device.default.renderer, linearizer=False)
with Profiling(PROFILE, fn="/tmp/rewrite.prof"): with Profiling(PROFILE, fn="/tmp/rewrite.prof"):
with Timing("***** model rewrite in "): with Timing("***** model rewrite in "):
rewritten_uops = [] rewritten_uops = []
for u in asts: for i,(k,u,rewrites) in enumerate(kernels):
rewritten_uops.append(apply_rewrites(u, rewrites)) with Timing(f"rewrite {i:2d} {k.name}{' '*(50-ansilen(k.name))}", enabled=getenv("VERBOSE", 0)):
rewritten_uops.append(apply_rewrites(u, rewrites))
if LINEARIZE: if LINEARIZE:
with Timing("***** model linearize in "): with Timing("***** model linearize in "):
+1 -1
View File
@@ -8,7 +8,7 @@ if __name__ == "__main__":
GlobalCounters.reset() GlobalCounters.reset()
t.softmax(-1, dtype="half", _single_kernel=True).realize() t.softmax(-1, dtype="half", _single_kernel=True).realize()
from tinygrad.codegen.opt.kernel import Kernel, Opt, OptOps from tinygrad.opt.kernel import Kernel, Opt, OptOps
from tinygrad.helpers import get_single_element from tinygrad.helpers import get_single_element
GlobalCounters.reset() GlobalCounters.reset()
si = get_single_element(t.softmax(-1, dtype="half", _single_kernel=True).schedule()) si = get_single_element(t.softmax(-1, dtype="half", _single_kernel=True).schedule())
+2 -2
View File
@@ -1,8 +1,8 @@
# ruff: noqa: E501 # ruff: noqa: E501
from tinygrad.codegen.opt.kernel import Kernel, Opt, OptOps from tinygrad.opt.kernel import Kernel, Opt, OptOps
from tinygrad.dtype import dtypes from tinygrad.dtype import dtypes
from tinygrad.engine.realize import CompiledRunner, get_program from tinygrad.engine.realize import CompiledRunner, get_program
from tinygrad.codegen.opt.search import bufs_from_lin from tinygrad.opt.search import bufs_from_lin
from tinygrad.uop.ops import UOp, Ops from tinygrad.uop.ops import UOp, Ops
from tinygrad.shape.shapetracker import ShapeTracker from tinygrad.shape.shapetracker import ShapeTracker
from tinygrad.shape.view import View from tinygrad.shape.view import View
+2 -2
View File
@@ -4,10 +4,10 @@ os.environ["VALIDATE_HCQ"]="1"
import unittest, random import unittest, random
import numpy as np import numpy as np
from tinygrad.codegen.opt.kernel import Kernel, KernelOptError from tinygrad.opt.kernel import Kernel, KernelOptError
from tinygrad.device import is_dtype_supported from tinygrad.device import is_dtype_supported
from tinygrad.uop.ops import UOp, Ops from tinygrad.uop.ops import UOp, Ops
from tinygrad.codegen.opt.search import Opt, OptOps from tinygrad.opt.search import Opt, OptOps
from tinygrad import Device, dtypes, Tensor from tinygrad import Device, dtypes, Tensor
from test.external.fuzz_linearizer import compare_linearizer, compare_states, get_fuzz_rawbuf_like from test.external.fuzz_linearizer import compare_linearizer, compare_states, get_fuzz_rawbuf_like
+1 -1
View File
@@ -3,7 +3,7 @@ from tinygrad.runtime.support.hip_comgr import compile_hip
from tinygrad import Tensor from tinygrad import Tensor
from tinygrad.device import Device from tinygrad.device import Device
from tinygrad.engine.schedule import create_schedule from tinygrad.engine.schedule import create_schedule
from tinygrad.codegen.opt.kernel import Kernel from tinygrad.opt.kernel import Kernel
class TestHIPCompileSpeed(unittest.TestCase): class TestHIPCompileSpeed(unittest.TestCase):
@unittest.skipIf(Device.DEFAULT != "HIP", "only run on HIP") @unittest.skipIf(Device.DEFAULT != "HIP", "only run on HIP")
+2 -2
View File
@@ -2,11 +2,11 @@ import unittest, struct, array, ctypes
from tinygrad import Device, dtypes, Tensor from tinygrad import Device, dtypes, Tensor
from tinygrad.helpers import to_mv from tinygrad.helpers import to_mv
from tinygrad.runtime.ops_nv import NVDevice, HWQueue from tinygrad.runtime.ops_nv import NVDevice, HWQueue
from tinygrad.codegen.opt.search import Opt, OptOps from tinygrad.opt.search import Opt, OptOps
from tinygrad.engine.realize import get_runner, CompiledRunner, get_program from tinygrad.engine.realize import get_runner, CompiledRunner, get_program
from test.external.fuzz_linearizer import get_fuzz_rawbufs from test.external.fuzz_linearizer import get_fuzz_rawbufs
from tinygrad.codegen.opt.kernel import Kernel from tinygrad.opt.kernel import Kernel
from tinygrad.uop.ops import LazyOp, Ops, ReduceOps, BufferOps, MemBuffer from tinygrad.uop.ops import LazyOp, Ops, ReduceOps, BufferOps, MemBuffer
from tinygrad.shape.shapetracker import ShapeTracker from tinygrad.shape.shapetracker import ShapeTracker
from tinygrad.shape.view import View from tinygrad.shape.view import View
+4 -7
View File
@@ -53,7 +53,6 @@ backend_test.exclude('test_dynamicquantizelinear_cpu')
backend_test.exclude('test_dynamicquantizelinear_expanded_cpu') backend_test.exclude('test_dynamicquantizelinear_expanded_cpu')
# BUG: ORT fails these with numerical error but we match ORT numerically # BUG: ORT fails these with numerical error but we match ORT numerically
# see: https://onnx.ai/backend-scoreboard/onnxruntime_details_stable.html
# tested in external_test_onnx_ops.py::TestMainOnnxOps.test_qlinearmatmul_2D_int8_float16 # tested in external_test_onnx_ops.py::TestMainOnnxOps.test_qlinearmatmul_2D_int8_float16
backend_test.exclude('test_qlinearmatmul_2D_int8_float16_cpu') backend_test.exclude('test_qlinearmatmul_2D_int8_float16_cpu')
# tested in external_test_onnx_ops.py::TestMainOnnxOps.test_qlinearmatmul_3D_int8_float16 # tested in external_test_onnx_ops.py::TestMainOnnxOps.test_qlinearmatmul_3D_int8_float16
@@ -66,10 +65,6 @@ backend_test.exclude('test_qlinearmatmul_3D_int8_float32_cpu')
backend_test.exclude('test_maxunpool_export_with_output_shape_cpu') backend_test.exclude('test_maxunpool_export_with_output_shape_cpu')
# tested in external_test_onnx_ops.py::TestMainOnnxOps.test_averagepool_3d_dilations_large_count_include_pad_is_1_ceil_mode_is_True # tested in external_test_onnx_ops.py::TestMainOnnxOps.test_averagepool_3d_dilations_large_count_include_pad_is_1_ceil_mode_is_True
backend_test.exclude('test_averagepool_3d_dilations_large_count_include_pad_is_1_ceil_mode_is_True_cpu') backend_test.exclude('test_averagepool_3d_dilations_large_count_include_pad_is_1_ceil_mode_is_True_cpu')
# tested in external_test_onnx_ops.py::TestMainOnnxOps.test_resize_downsample_scales_linear_align_corners
backend_test.exclude('test_resize_downsample_scales_linear_align_corners_cpu')
# tested in external_test_onnx_ops.py::TestMainOnnxOps.test_resize_downsample_scales_cubic_align_corners
backend_test.exclude('test_resize_downsample_scales_cubic_align_corners_cpu')
# about different dtypes # about different dtypes
if not is_dtype_supported(dtypes.float64): if not is_dtype_supported(dtypes.float64):
@@ -170,6 +165,10 @@ backend_test.exclude('test_deform_conv_*')
backend_test.exclude('test_lppool_*') backend_test.exclude('test_lppool_*')
backend_test.exclude('test_scan_*') backend_test.exclude('test_scan_*')
backend_test.exclude('test_split_to_sequence_*') backend_test.exclude('test_split_to_sequence_*')
backend_test.exclude('test_resize_downsample_scales_cubic_*') # unsure how to implement cubic
backend_test.exclude('test_resize_downsample_sizes_cubic_*') # unsure how to implement cubic
backend_test.exclude('test_resize_upsample_scales_cubic_*') # unsure how to implement cubic
backend_test.exclude('test_resize_upsample_sizes_cubic_*') # unsure how to implement cubic
backend_test.exclude('test_ai_onnx_ml_tree_ensemble_*') # https://github.com/onnx/onnx/blob/main/onnx/reference/ops/aionnxml/op_tree_ensemble.py#L121 backend_test.exclude('test_ai_onnx_ml_tree_ensemble_*') # https://github.com/onnx/onnx/blob/main/onnx/reference/ops/aionnxml/op_tree_ensemble.py#L121
# rest of the failing tests # rest of the failing tests
@@ -179,8 +178,6 @@ backend_test.exclude('test_resize_tf_crop_and_resize_axes_3_2_cpu') # tf_crop_an
backend_test.exclude('test_resize_tf_crop_and_resize_extrapolation_value_cpu') # tf_crop_and_resize value not implemented backend_test.exclude('test_resize_tf_crop_and_resize_extrapolation_value_cpu') # tf_crop_and_resize value not implemented
backend_test.exclude('test_resize_downsample_scales_linear_antialias_cpu') # antialias not implemented backend_test.exclude('test_resize_downsample_scales_linear_antialias_cpu') # antialias not implemented
backend_test.exclude('test_resize_downsample_sizes_linear_antialias_cpu') # antialias not implemented backend_test.exclude('test_resize_downsample_sizes_linear_antialias_cpu') # antialias not implemented
backend_test.exclude('test_resize_downsample_scales_cubic_antialias_cpu') # antialias not implemented
backend_test.exclude('test_resize_downsample_sizes_cubic_antialias_cpu') # antialias not implemented
backend_test.exclude('test_ai_onnx_ml_label_encoder_tensor_value_only_mapping_cpu') # bad data type string backend_test.exclude('test_ai_onnx_ml_label_encoder_tensor_value_only_mapping_cpu') # bad data type string
backend_test.exclude('test_ai_onnx_ml_label_encoder_tensor_mapping_cpu') # bad data type string backend_test.exclude('test_ai_onnx_ml_label_encoder_tensor_mapping_cpu') # bad data type string
+1 -43
View File
@@ -75,49 +75,6 @@ class TestMainOnnxOps(TestOnnxOps):
outputs = ["y"] outputs = ["y"]
self.helper_test_single_op("Gather", inputs, attributes, outputs) self.helper_test_single_op("Gather", inputs, attributes, outputs)
# NOTE: resize OP is sensitive to numerical errors
def _test_resize_scales(self, scale_values, **kwargs):
for sc in scale_values:
for ct_mode in ["half_pixel", "align_corners", "asymmetric", "pytorch_half_pixel", "half_pixel_symmetric"]:
with self.subTest(coordinate_transformation_mode=ct_mode, scale=sc, **kwargs):
X = np.array([[[[1, 2, 3, 4],
[5, 6, 7, 8],
[9,10,11,12]]]], dtype=np.float32)
scales = np.array([1.0, 1.0, sc, sc], dtype=np.float32)
inputs = {"X": X, "roi": np.array([], dtype=np.float32), "scales": scales}
attributes = {"coordinate_transformation_mode": ct_mode, **kwargs}
outputs = ["out"]
self.helper_test_single_op("Resize", inputs, attributes, outputs)
def test_resize_linear_mode(self):
self._test_resize_scales([0.01, 0.25, 0.5, 0.51, 0.6, 1.0, 1.5, 2.0, 3.5, 20.0], mode="linear")
def test_resize_nearest_mode(self):
# excluded 3.5 because some values divide into slight numerical differences, which when rounded gives wrong results
self._test_resize_scales([0.01, 0.25, 0.5, 0.51, 0.6, 1.0, 1.5, 2.0, 20.0], mode="nearest")
def test_resize_cubic_mode(self):
self._test_resize_scales([0.01, 0.25, 0.5, 0.51, 0.6, 1.0, 1.5, 2.0, 3.5, 20.0], mode="cubic", exclude_outside=1)
self._test_resize_scales([0.01, 0.25, 0.5, 0.51, 0.6, 1.0, 1.5, 2.0, 3.5, 20.0], mode="cubic", exclude_outside=0)
def test_resize_downsample_scales_linear_align_corners(self):
# https://github.com/onnx/onnx/blob/main/docs/Operators.md#examples-131
X = np.array([[[[1, 2, 3, 4], [5, 6, 7, 8]]]], dtype=np.float32)
scales = np.array([1.0, 1.0, 0.6, 0.6], dtype=np.float32)
inputs = {"X": X, "roi": np.array([], dtype=np.float32), "scales": scales}
attributes = {"mode": "linear", "coordinate_transformation_mode": "align_corners"}
outputs = ["out"]
self.helper_test_single_op("Resize", inputs, attributes, outputs)
def test_resize_downsample_scales_cubic_align_corners(self):
# https://github.com/onnx/onnx/blob/main/docs/Operators.md#examples-131
X = np.array([[[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]]]], dtype=np.float32)
scales = np.array([1.0, 1.0, 0.8, 0.8], dtype=np.float32)
inputs = {"X": X, "roi": np.array([], dtype=np.float32), "scales": scales}
attributes = {"mode": "cubic", "coordinate_transformation_mode": "align_corners"}
outputs = ["out"]
self.helper_test_single_op("Resize", inputs, attributes, outputs)
def test_maxunpool_export_with_output_shape(self): def test_maxunpool_export_with_output_shape(self):
# https://github.com/onnx/onnx/blob/main/docs/Operators.md#examples-91 # https://github.com/onnx/onnx/blob/main/docs/Operators.md#examples-91
xT = np.array([[[[5, 6], [7, 8]]]], dtype=np.float32) xT = np.array([[[[5, 6], [7, 8]]]], dtype=np.float32)
@@ -294,6 +251,7 @@ class TestTrainingOnnxOps(TestOnnxOps):
outputs = ["X_out", "V_out"] outputs = ["X_out", "V_out"]
self._validate_training("Momentum", onnx_fxn, inputs, attributes, outputs) self._validate_training("Momentum", onnx_fxn, inputs, attributes, outputs)
@unittest.expectedFailure # TODO: regression from removing StrEnum in Domain
def test_adam_t_greater_than_zero(self): def test_adam_t_greater_than_zero(self):
from onnx.backend.test.case.node.adam import apply_adam from onnx.backend.test.case.node.adam import apply_adam
for t in [1, 3, 100]: for t in [1, 3, 100]:
+5 -4
View File
@@ -3,7 +3,8 @@ import numpy as np
from tinygrad import dtypes, Tensor from tinygrad import dtypes, Tensor
from tinygrad.uop.ops import Ops from tinygrad.uop.ops import Ops
from tinygrad.device import is_dtype_supported from tinygrad.device import is_dtype_supported
from tinygrad.frontend.onnx import OnnxRunner, OnnxDataType from extra.onnx import data_types
from tinygrad.frontend.onnx import OnnxRunner
from hypothesis import given, strategies as st from hypothesis import given, strategies as st
# copied from test_const_folding.py # copied from test_const_folding.py
@@ -85,8 +86,8 @@ class TestOnnxRunner(unittest.TestCase):
output = runner({'inp': Tensor([1])})['output'] output = runner({'inp': Tensor([1])})['output']
np.testing.assert_equal(output.numpy(), weights + 1) np.testing.assert_equal(output.numpy(), weights + 1)
all_dtypes = list(OnnxDataType) all_dtypes = list(data_types.keys())
device_supported_dtypes = {odt for odt in OnnxDataType if is_dtype_supported(odt.to_dtype())} device_supported_dtypes = {odt for odt, dtype in data_types.items() if is_dtype_supported(dtype)}
class TestOnnxRunnerDtypes(unittest.TestCase): class TestOnnxRunnerDtypes(unittest.TestCase):
""" """
@@ -94,7 +95,7 @@ class TestOnnxRunnerDtypes(unittest.TestCase):
External tensors (inputs) preserve their original dtype - user must ensure compatibility with device. External tensors (inputs) preserve their original dtype - user must ensure compatibility with device.
""" """
def _get_expected_dtype(self, onnx_dtype: int, is_input: bool): def _get_expected_dtype(self, onnx_dtype: int, is_input: bool):
true_dtype = OnnxDataType(onnx_dtype).to_dtype() true_dtype = data_types[onnx_dtype]
# inputs always preserve their true dtype. # inputs always preserve their true dtype.
if is_input: if is_input:
return true_dtype return true_dtype
+2 -2
View File
@@ -2,11 +2,11 @@
import unittest import unittest
from tinygrad.uop.ops import UOp, Ops from tinygrad.uop.ops import UOp, Ops
from tinygrad.codegen.opt.search import Opt, OptOps from tinygrad.opt.search import Opt, OptOps
from tinygrad.dtype import dtypes from tinygrad.dtype import dtypes
from tinygrad.shape.shapetracker import ShapeTracker from tinygrad.shape.shapetracker import ShapeTracker
from tinygrad.shape.view import View from tinygrad.shape.view import View
from tinygrad.codegen.opt.kernel import Kernel from tinygrad.opt.kernel import Kernel
from test.external.fuzz_linearizer import run_linearizer from test.external.fuzz_linearizer import run_linearizer
+26 -19
View File
@@ -1,26 +1,33 @@
import random import random
import z3 from z3 import Int, Solver, sat
from tinygrad import dtypes from tinygrad import dtypes, Device
from tinygrad.uop.spec import z3_renderer, z3_cdiv from tinygrad.uop.ops import UOp, Ops, UPat, graph_rewrite, PatternMatcher
from tinygrad.uop.ops import UOp, graph_rewrite from tinygrad.codegen.optional import fast_idiv
from tinygrad.uop.decompositions import fast_idiv
random.seed(42) random.seed(42)
powers_of_two = [2**i for i in range(64)] z3_renderer = PatternMatcher([
(UPat((Ops.DEFINE_VAR, Ops.SPECIAL), name="x"), lambda x: UOp(Ops.NOOP, arg=x.arg[0])),
# Because fast_idiv only works for non-negative integers we can emulate machine arithmetic with modulo operations.
(UPat(Ops.SHR, src=UPat(Ops.NOOP), name="x"), lambda x: UOp(Ops.NOOP, arg=f"(({x.src[0].arg}/(2**{x.src[1].arg}))%{dtypes.max(x.dtype)+1})")),
(UPat(Ops.MUL, src=UPat(Ops.NOOP), name="x"), lambda x: UOp(Ops.NOOP, arg=f"(({x.src[0].arg}*{x.src[1].arg})%{dtypes.max(x.dtype)+1})")),
(UPat((Ops.CONST, Ops.VCONST), name="x"), lambda x: UOp(Ops.NOOP, arg=str(x.arg))),
(UPat(Ops.CAST, src=UPat(Ops.NOOP), name="x"), lambda x: UOp(Ops.NOOP, arg=f"{x.src[0].arg}")),
])
def render(self) -> str:
ret = graph_rewrite(self.simplify(), z3_renderer)
return ret.arg if ret.op is Ops.NOOP else str(ret)
if __name__ == "__main__": if __name__ == "__main__":
for i in range(10_000): x = Int('x')
if i % 1000 == 0: for _ in range(10_000):
print(f"Progress: {i}")
dt = random.choice(dtypes.ints) dt = random.choice(dtypes.ints)
u = UOp.variable('x', random.randint(dt.min, 0), random.randint(1, dt.max), dtype=dt) u = UOp(Ops.DEFINE_VAR, dt, arg=('x', 0, random.randint(1, dtypes.max(dt))), src=())
d = random.randint(1, max(1, u.arg[2])) d = random.randint(1, max(1, u.arg[2]))
if d in powers_of_two: continue
expr = fast_idiv(None, u, d) expr = fast_idiv(Device[Device.DEFAULT].renderer, u, d)
if expr is None: continue if expr is None: continue
solver = Solver()
solver = z3.Solver() solver.add(x>=u.arg[1], x<=u.arg[2])
z3_sink = graph_rewrite(expr.sink(u), z3_renderer, ctx=(solver, {})) if solver.check(eval(render(expr)) != x/d) == sat:
z3_expr, x = z3_sink.src[0].arg, z3_sink.src[1].arg assert False, f"Failed: {render(expr)} != x//{d} at x={solver.model()[x]}\nx={u}\nd={d}"
if solver.check(z3_expr != z3_cdiv(x, d)) == z3.sat:
assert False, f"Failed: {expr.render()} != x//{d} at x={solver.model()}\nx={u}\nd={d}\n{z3_expr=}\n{x/d=}"
+3 -3
View File
@@ -21,9 +21,9 @@ if os.getenv("VALIDATE_HCQ", 0) != 0:
from tinygrad import Tensor, Device, dtypes from tinygrad import Tensor, Device, dtypes
from tinygrad.tensor import _to_np_dtype from tinygrad.tensor import _to_np_dtype
from tinygrad.codegen.opt.kernel import Kernel from tinygrad.opt.kernel import Kernel
from tinygrad.codegen.opt.kernel import Opt, OptOps from tinygrad.opt.kernel import Opt, OptOps
from tinygrad.codegen.opt.search import get_kernel_actions, bufs_from_lin from tinygrad.opt.search import get_kernel_actions, bufs_from_lin
from tinygrad.engine.realize import CompiledRunner from tinygrad.engine.realize import CompiledRunner
from tinygrad.helpers import getenv, from_mv, prod, colored, Context, DEBUG, Timing from tinygrad.helpers import getenv, from_mv, prod, colored, Context, DEBUG, Timing
from tinygrad.uop.ops import UOp, Ops from tinygrad.uop.ops import UOp, Ops
+3 -10
View File
@@ -1,7 +1,6 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# compare kernels created by HEAD against master # compare kernels created by HEAD against master
import os, multiprocessing, logging, pickle, sqlite3, difflib, warnings, itertools, functools, base64, codecs import os, multiprocessing, logging, pickle, sqlite3, difflib, warnings, itertools, functools, base64, codecs
from dataclasses import replace
from typing import Callable, Any from typing import Callable, Any
ASSERT_DIFF = int((flag:="[pr]") in os.getenv("COMMIT_MESSAGE", flag) or flag in os.getenv("PR_TITLE", flag)) ASSERT_DIFF = int((flag:="[pr]") in os.getenv("COMMIT_MESSAGE", flag) or flag in os.getenv("PR_TITLE", flag))
@@ -12,9 +11,7 @@ try:
from tinygrad.renderer import Renderer, ProgramSpec from tinygrad.renderer import Renderer, ProgramSpec
from tinygrad.engine.realize import get_program from tinygrad.engine.realize import get_program
from tinygrad.uop.ops import UOp, Ops, KernelInfo from tinygrad.uop.ops import UOp, Ops, KernelInfo
from tinygrad.codegen.opt.kernel import Opt
from tinygrad.helpers import VERSION, Context, ContextVar, colored, db_connection, getenv, tqdm from tinygrad.helpers import VERSION, Context, ContextVar, colored, db_connection, getenv, tqdm
from tinygrad.device import Device
except ImportError as e: except ImportError as e:
print(repr(e)) print(repr(e))
exit(int(ASSERT_DIFF)) exit(int(ASSERT_DIFF))
@@ -50,13 +47,9 @@ def replay_kernelize(ret:dict[UOp, UOp], big_sink:UOp) -> tuple[str, str, tuple[
return "\n".join([f"{len(asts)} kernels", *asts]) return "\n".join([f"{len(asts)} kernels", *asts])
return to_str(new_sink), to_str(ret[big_sink]), (big_sink,) return to_str(new_sink), to_str(ret[big_sink]), (big_sink,)
def replay_get_program(p:ProgramSpec, ast:UOp, renderer:Renderer|None=None, opts:list[Opt]|None=None) -> tuple[str, str, tuple[Any, ...]]: def replay_get_program(p:ProgramSpec, ast:UOp, renderer:Renderer) -> tuple[str, str, tuple[Any, ...]]:
# NOTE: this always uses the opts_to_apply path input_ast = ast.replace(arg=KernelInfo(opts_to_apply=p.applied_opts, name=p.name)) if ast.arg is None else ast
sink_arg = ast.arg or KernelInfo(opts_to_apply=p.applied_opts) p2 = get_program(input_ast, renderer)
input_ast = ast.replace(arg=replace(sink_arg, name=p.name))
# if no renderer was provided, open the device to get it
if renderer is None: renderer = Device[p.device].renderer
p2 = get_program(input_ast, renderer=renderer)
def to_str(ret:ProgramSpec) -> str: def to_str(ret:ProgramSpec) -> str:
# PYTHON renderer pickles UOps, first unpickle and decode here # PYTHON renderer pickles UOps, first unpickle and decode here
if p.device.startswith("PYTHON"): return "\n".join([str(x) for x in pickle.loads(base64.b64decode(ret.src))]) if p.device.startswith("PYTHON"): return "\n".join([str(x) for x in pickle.loads(base64.b64decode(ret.src))])
+2 -2
View File
@@ -1,7 +1,7 @@
from tinygrad import Device from tinygrad import Device
from tinygrad.helpers import getenv, DEBUG, BEAM from tinygrad.helpers import getenv, DEBUG, BEAM
from tinygrad.codegen.opt.search import beam_search, bufs_from_lin from tinygrad.opt.search import beam_search, bufs_from_lin
from tinygrad.codegen.opt.heuristic import hand_coded_optimizations from tinygrad.opt.heuristic import hand_coded_optimizations
from extra.optimization.helpers import load_worlds, ast_str_to_lin, time_linearizer from extra.optimization.helpers import load_worlds, ast_str_to_lin, time_linearizer
if __name__ == "__main__": if __name__ == "__main__":
+2 -2
View File
@@ -2,8 +2,8 @@ from tinygrad import Device, dtypes
from tinygrad.helpers import getenv, colorize_float, DEBUG from tinygrad.helpers import getenv, colorize_float, DEBUG
from extra.optimization.helpers import load_worlds, ast_str_to_lin from extra.optimization.helpers import load_worlds, ast_str_to_lin
from test.external.fuzz_linearizer import get_fuzz_rawbufs from test.external.fuzz_linearizer import get_fuzz_rawbufs
from tinygrad.codegen.opt.heuristic import hand_coded_optimizations from tinygrad.opt.heuristic import hand_coded_optimizations
from tinygrad.codegen.opt.search import bufs_from_lin from tinygrad.opt.search import bufs_from_lin
from tinygrad.engine.realize import CompiledRunner, get_program from tinygrad.engine.realize import CompiledRunner, get_program
from tinygrad.tensor import _to_np_dtype from tinygrad.tensor import _to_np_dtype
from tinygrad.runtime.ops_amd import AMDDevice from tinygrad.runtime.ops_amd import AMDDevice
+2 -2
View File
@@ -2,8 +2,8 @@ from tinygrad import Device, dtypes
from tinygrad.helpers import getenv, colorize_float from tinygrad.helpers import getenv, colorize_float
from extra.optimization.helpers import load_worlds, ast_str_to_lin from extra.optimization.helpers import load_worlds, ast_str_to_lin
from test.external.fuzz_linearizer import get_fuzz_rawbufs from test.external.fuzz_linearizer import get_fuzz_rawbufs
from tinygrad.codegen.opt.heuristic import hand_coded_optimizations from tinygrad.opt.heuristic import hand_coded_optimizations
from tinygrad.codegen.opt.search import bufs_from_lin from tinygrad.opt.search import bufs_from_lin
from tinygrad.engine.realize import CompiledRunner, get_program from tinygrad.engine.realize import CompiledRunner, get_program
from tinygrad.tensor import _to_np_dtype from tinygrad.tensor import _to_np_dtype
import numpy as np import numpy as np
+2 -2
View File
@@ -1,10 +1,10 @@
import itertools import itertools
from tinygrad import Device from tinygrad import Device
from tinygrad.engine.realize import CompiledRunner, get_program from tinygrad.engine.realize import CompiledRunner, get_program
from tinygrad.codegen.opt.heuristic import hand_coded_optimizations from tinygrad.opt.heuristic import hand_coded_optimizations
from tinygrad.helpers import getenv, colorize_float from tinygrad.helpers import getenv, colorize_float
from extra.optimization.helpers import load_worlds, ast_str_to_lin from extra.optimization.helpers import load_worlds, ast_str_to_lin
from tinygrad.codegen.opt.search import bufs_from_lin from tinygrad.opt.search import bufs_from_lin
from tinygrad.runtime.ops_cuda import PTXCompiler, PTXRenderer, CUDACompiler from tinygrad.runtime.ops_cuda import PTXCompiler, PTXRenderer, CUDACompiler
if __name__ == "__main__": if __name__ == "__main__":
+1 -1
View File
@@ -3,7 +3,7 @@ from collections import defaultdict
from extra.optimization.helpers import kern_str_to_lin, time_linearizer from extra.optimization.helpers import kern_str_to_lin, time_linearizer
from test.external.fuzz_linearizer import compare_linearizer from test.external.fuzz_linearizer import compare_linearizer
from tinygrad.helpers import colored from tinygrad.helpers import colored
from tinygrad.codegen.opt.kernel import Kernel from tinygrad.opt.kernel import Kernel
# Use this with the LOGKERNS options to verify that all executed kernels are valid and evaluate to the same ground truth results # Use this with the LOGKERNS options to verify that all executed kernels are valid and evaluate to the same ground truth results
-3
View File
@@ -87,19 +87,16 @@ class AMDDriver(VirtDriver):
functools.partial(TextFileDesc, text=gpu_props.format(drm_render_minor=gpu_id))), functools.partial(TextFileDesc, text=gpu_props.format(drm_render_minor=gpu_id))),
VirtFile(f'/sys/class/drm/renderD{gpu_id}/device/ip_discovery/die/0', VirtFile(f'/sys/class/drm/renderD{gpu_id}/device/ip_discovery/die/0',
functools.partial(DirFileDesc, child_names=[str(am.GC_HWID), str(am.SDMA0_HWID), str(am.NBIF_HWID)])), functools.partial(DirFileDesc, child_names=[str(am.GC_HWID), str(am.SDMA0_HWID), str(am.NBIF_HWID)])),
VirtFile(f'/sys/class/drm/renderD{gpu_id}/device/ip_discovery/die/0/{am.GC_HWID}', functools.partial(DirFileDesc, child_names=['0'])),
VirtFile(f'/sys/class/drm/renderD{gpu_id}/device/ip_discovery/die/0/{am.GC_HWID}/0/major', functools.partial(TextFileDesc, text='11')), VirtFile(f'/sys/class/drm/renderD{gpu_id}/device/ip_discovery/die/0/{am.GC_HWID}/0/major', functools.partial(TextFileDesc, text='11')),
VirtFile(f'/sys/class/drm/renderD{gpu_id}/device/ip_discovery/die/0/{am.GC_HWID}/0/minor', functools.partial(TextFileDesc, text='0')), VirtFile(f'/sys/class/drm/renderD{gpu_id}/device/ip_discovery/die/0/{am.GC_HWID}/0/minor', functools.partial(TextFileDesc, text='0')),
VirtFile(f'/sys/class/drm/renderD{gpu_id}/device/ip_discovery/die/0/{am.GC_HWID}/0/revision', functools.partial(TextFileDesc, text='0')), VirtFile(f'/sys/class/drm/renderD{gpu_id}/device/ip_discovery/die/0/{am.GC_HWID}/0/revision', functools.partial(TextFileDesc, text='0')),
VirtFile(f'/sys/class/drm/renderD{gpu_id}/device/ip_discovery/die/0/{am.GC_HWID}/0/base_addr', VirtFile(f'/sys/class/drm/renderD{gpu_id}/device/ip_discovery/die/0/{am.GC_HWID}/0/base_addr',
functools.partial(TextFileDesc, text='0x00001260\n0x0000A000\n0x0001C000\n0x02402C00')), functools.partial(TextFileDesc, text='0x00001260\n0x0000A000\n0x0001C000\n0x02402C00')),
VirtFile(f'/sys/class/drm/renderD{gpu_id}/device/ip_discovery/die/0/{am.SDMA0_HWID}', functools.partial(DirFileDesc, child_names=['0'])),
VirtFile(f'/sys/class/drm/renderD{gpu_id}/device/ip_discovery/die/0/{am.SDMA0_HWID}/0/major', functools.partial(TextFileDesc, text='6')), VirtFile(f'/sys/class/drm/renderD{gpu_id}/device/ip_discovery/die/0/{am.SDMA0_HWID}/0/major', functools.partial(TextFileDesc, text='6')),
VirtFile(f'/sys/class/drm/renderD{gpu_id}/device/ip_discovery/die/0/{am.SDMA0_HWID}/0/minor', functools.partial(TextFileDesc, text='0')), VirtFile(f'/sys/class/drm/renderD{gpu_id}/device/ip_discovery/die/0/{am.SDMA0_HWID}/0/minor', functools.partial(TextFileDesc, text='0')),
VirtFile(f'/sys/class/drm/renderD{gpu_id}/device/ip_discovery/die/0/{am.SDMA0_HWID}/0/revision', functools.partial(TextFileDesc, text='0')), VirtFile(f'/sys/class/drm/renderD{gpu_id}/device/ip_discovery/die/0/{am.SDMA0_HWID}/0/revision', functools.partial(TextFileDesc, text='0')),
VirtFile(f'/sys/class/drm/renderD{gpu_id}/device/ip_discovery/die/0/{am.SDMA0_HWID}/0/base_addr', VirtFile(f'/sys/class/drm/renderD{gpu_id}/device/ip_discovery/die/0/{am.SDMA0_HWID}/0/base_addr',
functools.partial(TextFileDesc, text='0x00001260\n0x0000A000\n0x0001C000\n0x02402C00')), functools.partial(TextFileDesc, text='0x00001260\n0x0000A000\n0x0001C000\n0x02402C00')),
VirtFile(f'/sys/class/drm/renderD{gpu_id}/device/ip_discovery/die/0/{am.NBIF_HWID}', functools.partial(DirFileDesc, child_names=['0'])),
VirtFile(f'/sys/class/drm/renderD{gpu_id}/device/ip_discovery/die/0/{am.NBIF_HWID}/0/major', functools.partial(TextFileDesc, text='4')), VirtFile(f'/sys/class/drm/renderD{gpu_id}/device/ip_discovery/die/0/{am.NBIF_HWID}/0/major', functools.partial(TextFileDesc, text='4')),
VirtFile(f'/sys/class/drm/renderD{gpu_id}/device/ip_discovery/die/0/{am.NBIF_HWID}/0/minor', functools.partial(TextFileDesc, text='3')), VirtFile(f'/sys/class/drm/renderD{gpu_id}/device/ip_discovery/die/0/{am.NBIF_HWID}/0/minor', functools.partial(TextFileDesc, text='3')),
VirtFile(f'/sys/class/drm/renderD{gpu_id}/device/ip_discovery/die/0/{am.NBIF_HWID}/0/revision', functools.partial(TextFileDesc, text='0')), VirtFile(f'/sys/class/drm/renderD{gpu_id}/device/ip_discovery/die/0/{am.NBIF_HWID}/0/revision', functools.partial(TextFileDesc, text='0')),
+2 -5
View File
@@ -1,7 +1,7 @@
import ctypes, time import ctypes, time
from test.mockgpu.gpu import VirtGPU from test.mockgpu.gpu import VirtGPU
from tinygrad.helpers import getbits, to_mv, init_c_struct_t from tinygrad.helpers import getbits, to_mv, init_c_struct_t
import tinygrad.runtime.autogen.amd_gpu as amd_gpu, tinygrad.runtime.autogen.am.pm4_nv as pm4 import tinygrad.runtime.autogen.amd_gpu as amd_gpu, tinygrad.runtime.autogen.am.pm4_nv as pm4, tinygrad.runtime.autogen.am.soc21 as soc21
SDMA_MAX_COPY_SIZE = 0x400000 SDMA_MAX_COPY_SIZE = 0x400000
@@ -14,9 +14,6 @@ regSQ_THREAD_TRACE_BUF0_SIZE = 0x39e9 + amd_gpu.GC_BASE__INST0_SEG1
regSQ_THREAD_TRACE_WPTR = 0x39ef + amd_gpu.GC_BASE__INST0_SEG1 regSQ_THREAD_TRACE_WPTR = 0x39ef + amd_gpu.GC_BASE__INST0_SEG1
regSQ_THREAD_TRACE_STATUS = 0x39f4 + amd_gpu.GC_BASE__INST0_SEG1 regSQ_THREAD_TRACE_STATUS = 0x39f4 + amd_gpu.GC_BASE__INST0_SEG1
class SQTT_EVENTS:
THREAD_TRACE_FINISH = 0x00000037
CACHE_FLUSH_AND_INV_TS_EVENT = 0x14 CACHE_FLUSH_AND_INV_TS_EVENT = 0x14
WAIT_REG_MEM_FUNCTION_ALWAYS = 0 WAIT_REG_MEM_FUNCTION_ALWAYS = 0
@@ -211,7 +208,7 @@ class PM4Executor(AMDQueue):
assert n == 0 assert n == 0
event_dw = self._next_dword() event_dw = self._next_dword()
match (event_dw & 0xFF): # event type match (event_dw & 0xFF): # event type
case SQTT_EVENTS.THREAD_TRACE_FINISH: case soc21.THREAD_TRACE_FINISH:
old_idx = self.gpu.regs.grbm_index old_idx = self.gpu.regs.grbm_index
for se in range(self.gpu.regs.n_se): for se in range(self.gpu.regs.n_se):
self.gpu.regs.grbm_index = 0b011 << 29 | se << 16 # select se, broadcast sa and instance self.gpu.regs.grbm_index = 0b011 << 29 | se << 16 # select se, broadcast sa and instance
+1 -41
View File
@@ -9,15 +9,7 @@ except ModuleNotFoundError:
raise unittest.SkipTest("onnx not installed, skipping onnx test") raise unittest.SkipTest("onnx not installed, skipping onnx test")
from tinygrad.frontend.onnx import OnnxRunner from tinygrad.frontend.onnx import OnnxRunner
from tinygrad.tensor import Tensor from tinygrad.tensor import Tensor
from tinygrad.device import Device from tinygrad.helpers import CI, fetch, temp
from tinygrad.helpers import CI, fetch, temp, Context
try:
from extra.onnx_helpers import validate
from extra.huggingface_onnx.huggingface_manager import DOWNLOADS_DIR, snapshot_download_with_retry
HUGGINGFACE_AVAILABLE = True
except ModuleNotFoundError:
HUGGINGFACE_AVAILABLE = False
def run_onnx_torch(onnx_model, inputs): def run_onnx_torch(onnx_model, inputs):
import torch import torch
@@ -32,7 +24,6 @@ OPENPILOT_MODEL = "https://github.com/commaai/openpilot/raw/v0.9.4/selfdrive/mod
np.random.seed(1337) np.random.seed(1337)
class TestOnnxModel(unittest.TestCase): class TestOnnxModel(unittest.TestCase):
@unittest.skip("this isn't a test, it can't fail")
def test_benchmark_openpilot_model(self): def test_benchmark_openpilot_model(self):
onnx_model = fetch(OPENPILOT_MODEL) onnx_model = fetch(OPENPILOT_MODEL)
run_onnx = OnnxRunner(onnx_model) run_onnx = OnnxRunner(onnx_model)
@@ -146,36 +137,5 @@ class TestOnnxModel(unittest.TestCase):
print(cls, _LABELS[cls]) print(cls, _LABELS[cls])
assert "car" in _LABELS[cls] or _LABELS[cls] == "convertible" assert "car" in _LABELS[cls] or _LABELS[cls] == "convertible"
@unittest.skipUnless(HUGGINGFACE_AVAILABLE and Device.DEFAULT == "METAL", "only run on METAL")
class TestHuggingFaceOnnxModels(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls._ctx = Context(MAX_BUFFER_SIZE=0)
cls._ctx.__enter__()
@classmethod
def tearDownClass(cls):
cls._ctx.__exit__()
def _validate(self, repo_id, model_file, custom_inputs, rtol=1e-4, atol=1e-4):
onnx_model_path = snapshot_download_with_retry(
repo_id=repo_id,
allow_patterns=["*.onnx", "*.onnx_data"],
cache_dir=str(DOWNLOADS_DIR)
)
onnx_model_path = onnx_model_path / model_file
file_size = onnx_model_path.stat().st_size
print(f"Validating model: {repo_id}/{model_file} ({file_size/1e6:.2f}M)")
validate(onnx_model_path, custom_inputs, rtol=rtol, atol=atol)
def test_xlm_roberta_large(self):
repo_id = "FacebookAI/xlm-roberta-large"
model_file = "onnx/model.onnx"
custom_inputs = {
"input_ids": np.random.randint(0, 250002, (1, 11), dtype=np.int64),
"attention_mask": np.ones((1, 11), dtype=np.int64),
}
self._validate(repo_id, model_file, custom_inputs)
if __name__ == "__main__": if __name__ == "__main__":
unittest.main() unittest.main()
+1 -1
View File
@@ -16,7 +16,7 @@ TRANSCRIPTION_2 = "a slightly longer audio file so that we can test batch transc
TEST_FILE_3_URL = 'https://homepage.ntu.edu.tw/~karchung/miniconversations/mc45.mp3' TEST_FILE_3_URL = 'https://homepage.ntu.edu.tw/~karchung/miniconversations/mc45.mp3'
TRANSCRIPTION_3 = "Just lie back and relax. Is the level of pressure about right? Yes, it's fine, and I'd like conditioner please. Sure. I'm going to start the second lathering now. Would you like some Q-tips? How'd you like it cut? I'd like my bangs and the back trimmed, and I'd like the rest thinned out a bit and layered. Where would you like the part? On the left, right about here. Here, have a look. What do you think? It's fine. Here's a thousand anti-dollars. It's 30-ant extra for the rants. Here's your change and receipt. Thank you, and please come again. So how do you like it? It could have been worse, but you'll notice that I didn't ask her for her card. Hmm, yeah. Maybe you can try that place over there next time." # noqa: E501 TRANSCRIPTION_3 = "Just lie back and relax. Is the level of pressure about right? Yes, it's fine, and I'd like conditioner please. Sure. I'm going to start the second lathering now. Would you like some Q-tips? How'd you like it cut? I'd like my bangs and the back trimmed, and I'd like the rest thinned out a bit and layered. Where would you like the part? On the left, right about here. Here, have a look. What do you think? It's fine. Here's a thousand anti-dollars. It's 30-ant extra for the rants. Here's your change and receipt. Thank you, and please come again. So how do you like it? It could have been worse, but you'll notice that I didn't ask her for her card. Hmm, yeah. Maybe you can try that place over there next time." # noqa: E501
@unittest.skipIf(Device.DEFAULT in ["CPU", "LLVM"], "slow") @unittest.skipIf(CI and Device.DEFAULT in ["CPU"], "slow")
@unittest.skipUnless(is_dtype_supported(dtypes.float16), "need float16 support") @unittest.skipUnless(is_dtype_supported(dtypes.float16), "need float16 support")
class TestWhisper(unittest.TestCase): class TestWhisper(unittest.TestCase):
@classmethod @classmethod
+8 -6
View File
@@ -3,11 +3,10 @@ import numpy as np
from tinygrad import Tensor, GlobalCounters, dtypes, nn, Device, Variable from tinygrad import Tensor, GlobalCounters, dtypes, nn, Device, Variable
from tinygrad.helpers import CI, Context, getenv from tinygrad.helpers import CI, Context, getenv
from tinygrad.engine.realize import run_schedule from tinygrad.engine.realize import run_schedule
from tinygrad.codegen.opt.kernel import Opt, OptOps, Kernel, KernelOptError from tinygrad.opt.kernel import Opt, OptOps, Kernel, KernelOptError
from tinygrad.engine.realize import CompiledRunner, ExecItem, get_program from tinygrad.engine.realize import CompiledRunner, ExecItem, get_program
from tinygrad.codegen.opt.search import get_kernel_actions from tinygrad.opt.search import get_kernel_actions
from tinygrad.uop.ops import Ops from tinygrad.uop.ops import Ops
from tinygrad.codegen import apply_rewrites, rewrites_for_views
class TestArange(unittest.TestCase): class TestArange(unittest.TestCase):
def _get_flops(self, N, opts=None): def _get_flops(self, N, opts=None):
@@ -15,7 +14,10 @@ class TestArange(unittest.TestCase):
tt = Tensor.arange(N) tt = Tensor.arange(N)
sched = tt.schedule() sched = tt.schedule()
self.assertEqual(len(sched), 1) self.assertEqual(len(sched), 1)
p = get_program(sched[-1].ast, opts=opts) k = Kernel(sched[-1].ast)
if opts is not None:
for o in opts: k.apply_opt(o)
p = get_program(k.get_optimized_ast(), k.opts)
print(p.name) print(p.name)
#print(p.src) #print(p.src)
ExecItem(CompiledRunner(p), [tt.uop.buffer]).run() ExecItem(CompiledRunner(p), [tt.uop.buffer]).run()
@@ -50,11 +52,11 @@ class TestArange(unittest.TestCase):
def test_complexity_w_local_and_padto(self): return self.test_complexity([Opt(OptOps.LOCAL, 0, 16), Opt(OptOps.PADTO, axis=1, arg=32)]) def test_complexity_w_local_and_padto(self): return self.test_complexity([Opt(OptOps.LOCAL, 0, 16), Opt(OptOps.PADTO, axis=1, arg=32)])
def test_all_opts(self, opts=None, exclude=None): def test_all_opts(self, opts=None, exclude=None):
k = Kernel(apply_rewrites(Tensor.arange(256).schedule()[-1].ast, rewrites_for_views)) k = Kernel(Tensor.arange(256).schedule()[-1].ast)
if opts is not None: if opts is not None:
for o in opts: k.apply_opt(o) for o in opts: k.apply_opt(o)
all_opts_256 = [kk.applied_opts for kk in get_kernel_actions(k, include_0=False).values()] all_opts_256 = [kk.applied_opts for kk in get_kernel_actions(k, include_0=False).values()]
k = Kernel(apply_rewrites(Tensor.arange(2560).schedule()[-1].ast, rewrites_for_views)) k = Kernel(Tensor.arange(2560).schedule()[-1].ast)
if opts is not None: if opts is not None:
for o in opts: k.apply_opt(o) for o in opts: k.apply_opt(o)
all_opts_2560 = [kk.applied_opts for kk in get_kernel_actions(k, include_0=False).values()] all_opts_2560 = [kk.applied_opts for kk in get_kernel_actions(k, include_0=False).values()]
+1 -16
View File
@@ -1,10 +1,7 @@
import unittest, io import unittest
from contextlib import redirect_stdout
from tinygrad import Tensor, dtypes, Device from tinygrad import Tensor, dtypes, Device
from tinygrad.helpers import OSX
from tinygrad.engine.realize import lower_schedule from tinygrad.engine.realize import lower_schedule
from tinygrad.device import is_dtype_supported from tinygrad.device import is_dtype_supported
from tinygrad.engine.realize import get_program
class TestCompileFailures(unittest.TestCase): class TestCompileFailures(unittest.TestCase):
def compile(self, out:Tensor): def compile(self, out:Tensor):
@@ -17,17 +14,5 @@ class TestCompileFailures(unittest.TestCase):
def test_add_max_uchar(self): def test_add_max_uchar(self):
self.compile((Tensor.empty(1024, dtype='uint8') + Tensor.empty(1024, dtype='uint8')).max()) self.compile((Tensor.empty(1024, dtype='uint8') + Tensor.empty(1024, dtype='uint8')).max())
class TestDisassembly(unittest.TestCase):
# TODO: fails on llvm. llvm.LLVMGetHostCPUName() returns "generic"
@unittest.skipUnless(Device.DEFAULT in ("CPU",) and OSX, "m series cpus support fp16 arithmetic")
def test_float16_alu(self):
c = Tensor([1], dtype=dtypes.float16) + Tensor([1], dtype=dtypes.float16)
s = c.schedule()[-1]
p = get_program(s.ast, Device[Device.DEFAULT].renderer)
lib = Device[Device.DEFAULT].compiler.compile(p.src)
out = io.StringIO()
with redirect_stdout(out): Device[Device.DEFAULT].compiler.disassemble(lib)
assert "fcvt" not in out.getvalue()
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()
+17 -10
View File
@@ -139,16 +139,18 @@ class TestBitcastConstFolding(unittest.TestCase):
class TestIndexingConstFolding(unittest.TestCase): class TestIndexingConstFolding(unittest.TestCase):
def test_scalar_index(self): def test_scalar_index(self):
t = Tensor.arange(16).float().reshape(1,1,4,4).realize() t = Tensor.arange(16).float().reshape(1,1,4,4).realize()
_check_ast_count(1, t[:,:,Tensor(1),:]) # TODO: fold these
_check_ast_count(1, t[:,:,Tensor(1)+2,:]) _check_ast_count(2, t[:,:,Tensor(1),:])
_check_ast_count(1, t[:,:,Tensor(1),Tensor(0)]) _check_ast_count(2, t[:,:,Tensor(1)+2,:])
_check_ast_count(2, t[:,:,Tensor(1),Tensor(0)])
@unittest.expectedFailure
def test_const_tensor_index(self): def test_const_tensor_index(self):
# TODO: these can be 0, implement const tensor folded indexing # TODO: implement const tensor folded indexing
t = Tensor.arange(16).float().reshape(1,1,4,4).realize() t = Tensor.arange(16).float().reshape(1,1,4,4).realize()
_check_ast_count(1, t[:,:,Tensor.ones(2,1,dtype=dtypes.int),:]) _check_ast_count(0, t[:,:,Tensor.ones(2,1),:])
_check_ast_count(1, t[:,:,Tensor.ones(1,2,dtype=dtypes.int)+2,:]) _check_ast_count(0, t[:,:,Tensor.ones(1,2)+2,:])
_check_ast_count(1, t[:,:,Tensor.ones(1,1,dtype=dtypes.int),Tensor.zeros(2,1,2,dtype=dtypes.int)]) _check_ast_count(0, t[:,:,Tensor.ones(1,1),Tensor.zeros(2,1,2)])
class TestMovedConstFolding(unittest.TestCase): class TestMovedConstFolding(unittest.TestCase):
def test_add_shrunk_zero(self): def test_add_shrunk_zero(self):
@@ -289,12 +291,17 @@ class TestMultiConstFolding(unittest.TestCase):
np.testing.assert_equal((t + zero).numpy(), np.arange(16)) np.testing.assert_equal((t + zero).numpy(), np.arange(16))
np.testing.assert_equal((t * zero).numpy(), [0] * 16) np.testing.assert_equal((t * zero).numpy(), [0] * 16)
np.testing.assert_equal((t * one).numpy(), np.arange(16)) np.testing.assert_equal((t * one).numpy(), np.arange(16))
def test_multi_todo_pow(self):
ds = tuple(f"{Device.DEFAULT}:{i}" for i in range(4))
t = Tensor.arange(16).float().to(ds).realize()
zero = Tensor.zeros(16).to(ds).realize()
one = Tensor.ones(16).to(ds).realize()
# TODO: fix pow folding
_check_ast_count(0, t ** zero) _check_ast_count(0, t ** zero)
_check_ast_count(0, t ** one) _check_ast_count(0, t ** one)
_check_ast_count(0, one ** t) _check_ast_count(0, one ** t)
np.testing.assert_equal((t ** zero).numpy(), [1] * 16)
np.testing.assert_equal((t ** one).numpy(), np.arange(16))
np.testing.assert_equal((one ** t).numpy(), [1] * 16)
class TestTautologicalCompare(unittest.TestCase): class TestTautologicalCompare(unittest.TestCase):
# without const folding, these would have triggered -Wtautological-compare in clang # without const folding, these would have triggered -Wtautological-compare in clang
@@ -3,7 +3,7 @@ from tinygrad import Tensor, Device, TinyJit
from tinygrad.helpers import Timing, CI, OSX from tinygrad.helpers import Timing, CI, OSX
import multiprocessing.shared_memory as shared_memory import multiprocessing.shared_memory as shared_memory
N = 256 N = 256 if CI else 4096
class TestCopySpeed(unittest.TestCase): class TestCopySpeed(unittest.TestCase):
@classmethod @classmethod
def setUpClass(cls): Device[Device.DEFAULT].synchronize() def setUpClass(cls): Device[Device.DEFAULT].synchronize()
+4 -1
View File
@@ -62,6 +62,7 @@ class TestNaNEdgeCases(unittest.TestCase):
class TestEmptyTensorEdgeCases(unittest.TestCase): class TestEmptyTensorEdgeCases(unittest.TestCase):
# we don't need more of these # we don't need more of these
@unittest.expectedFailure
def test_sort_empty(self): def test_sort_empty(self):
# Sorting an empty tensor works in PyTorch and should return empty # Sorting an empty tensor works in PyTorch and should return empty
# values and indices. tinygrad raises an error instead. # values and indices. tinygrad raises an error instead.
@@ -218,6 +219,7 @@ class TestAssignIssues(unittest.TestCase):
t.shrink(((1, 3), (1, 3))).assign(Tensor.ones(2, 2)) t.shrink(((1, 3), (1, 3))).assign(Tensor.ones(2, 2))
np.testing.assert_allclose(t.numpy(), torch_tensor.numpy()) np.testing.assert_allclose(t.numpy(), torch_tensor.numpy())
@unittest.expectedFailure
def test_assign_broadcast(self): def test_assign_broadcast(self):
# broadcasting during assign should behave like PyTorch # broadcasting during assign should behave like PyTorch
torch_tensor = torch.zeros(3, 5) torch_tensor = torch.zeros(3, 5)
@@ -256,11 +258,12 @@ class TestEdgeCases(unittest.TestCase):
out = Tensor(arr).pad((1, -1, 1, -1), mode='circular') out = Tensor(arr).pad((1, -1, 1, -1), mode='circular')
np.testing.assert_equal(out.numpy(), torch_out.numpy()) np.testing.assert_equal(out.numpy(), torch_out.numpy())
@unittest.expectedFailure
def test_arange_float_step(self): def test_arange_float_step(self):
# float steps should match PyTorch exactly # float steps should match PyTorch exactly
torch_out = torch.arange(0, 2, 0.3).numpy() torch_out = torch.arange(0, 2, 0.3).numpy()
out = Tensor.arange(0, 2, 0.3).numpy() out = Tensor.arange(0, 2, 0.3).numpy()
np.testing.assert_allclose(out, torch_out, atol=1e-7) np.testing.assert_allclose(out, torch_out)
@unittest.skip("this is flaky") @unittest.skip("this is flaky")
@unittest.expectedFailure @unittest.expectedFailure
+5 -3
View File
@@ -6,7 +6,7 @@ from tinygrad.runtime.support.hcq import HCQCompiled, HCQBuffer
from tinygrad.runtime.autogen import libc from tinygrad.runtime.autogen import libc
from tinygrad.runtime.support.system import PCIIfaceBase from tinygrad.runtime.support.system import PCIIfaceBase
from tinygrad.engine.realize import get_runner, CompiledRunner, get_program from tinygrad.engine.realize import get_runner, CompiledRunner, get_program
from tinygrad.codegen.opt.kernel import Opt, OptOps from tinygrad.opt.kernel import Kernel, Opt, OptOps
from tinygrad import Variable from tinygrad import Variable
MOCKGPU = getenv("MOCKGPU") MOCKGPU = getenv("MOCKGPU")
@@ -163,8 +163,10 @@ class TestHCQ(unittest.TestCase):
a = Tensor.randint((3, 3, 3), dtype=dtypes.int, device=Device.DEFAULT).realize() a = Tensor.randint((3, 3, 3), dtype=dtypes.int, device=Device.DEFAULT).realize()
b = a + 1 b = a + 1
si = b.schedule()[-1] si = b.schedule()[-1]
k = Kernel(si.ast, opts=TestHCQ.d0.renderer)
for i in range(3): k.apply_opt(Opt(op=OptOps.LOCAL, axis=0, arg=3))
runner = CompiledRunner(get_program(si.ast, TestHCQ.d0.renderer, opts=[Opt(op=OptOps.LOCAL, axis=0, arg=3) for _ in range(3)])) runner = CompiledRunner(get_program(k.get_optimized_ast(), k.opts))
zb = Buffer(Device.DEFAULT, 3 * 3 * 3, dtypes.int, options=BufferSpec(cpu_access=True, nolru=True)).ensure_allocated() zb = Buffer(Device.DEFAULT, 3 * 3 * 3, dtypes.int, options=BufferSpec(cpu_access=True, nolru=True)).ensure_allocated()
zt = Buffer(Device.DEFAULT, 3 * 3 * 3, dtypes.int, options=BufferSpec(cpu_access=True, nolru=True)).ensure_allocated() zt = Buffer(Device.DEFAULT, 3 * 3 * 3, dtypes.int, options=BufferSpec(cpu_access=True, nolru=True)).ensure_allocated()
@@ -336,7 +338,7 @@ class TestHCQ(unittest.TestCase):
et = float(sig_en.timestamp - sig_st.timestamp) et = float(sig_en.timestamp - sig_st.timestamp)
print(f"exec kernel time: {et:.2f} us") print(f"exec kernel time: {et:.2f} us")
assert 0.1 <= et <= (100000 if MOCKGPU or Device.DEFAULT in {"CPU", "LLVM"} else 100) assert 0.1 <= et <= (15000 if MOCKGPU or Device.DEFAULT in {"CPU", "LLVM"} else 100)
def test_speed_copy_bandwidth(self): def test_speed_copy_bandwidth(self):
if TestHCQ.d0.hw_copy_queue_t is None: self.skipTest("device does not support copy queue") if TestHCQ.d0.hw_copy_queue_t is None: self.skipTest("device does not support copy queue")
+4 -1
View File
@@ -718,6 +718,8 @@ class TestJitGraphSplit(unittest.TestCase):
def ji_xfer(self): return {"type": "xfer"} def ji_xfer(self): return {"type": "xfer"}
def test_jit_split_simple(self): def test_jit_split_simple(self):
if Device.DEFAULT == "REMOTE": raise unittest.SkipTest("REMOTE gpu is broken")
@TinyJit @TinyJit
def f(inp): def f(inp):
op0 = self.compute(Device.DEFAULT, inp) op0 = self.compute(Device.DEFAULT, inp)
@@ -790,9 +792,9 @@ class TestJitGraphSplit(unittest.TestCase):
multigraph=[self.ji_graph(5)], multigraph=[self.ji_graph(5)],
hcqgraph=[self.ji_graph(5)]) hcqgraph=[self.ji_graph(5)])
@unittest.skip("flaky")
def test_jit_multidev_xfer(self): def test_jit_multidev_xfer(self):
if Device.DEFAULT in {"CPU", "LLVM"}: raise unittest.SkipTest("CPU/LLVM is not a valid default device for this test (zero-copies)") if Device.DEFAULT in {"CPU", "LLVM"}: raise unittest.SkipTest("CPU/LLVM is not a valid default device for this test (zero-copies)")
if Device.DEFAULT == "METAL" or REAL_DEV == "METAL": raise unittest.SkipTest("Metal is flaky, with multidevice (same as metal llama 4gpu?)")
try: Device[f"{Device.DEFAULT}:1"] try: Device[f"{Device.DEFAULT}:1"]
except Exception: raise unittest.SkipTest("no multidevice") except Exception: raise unittest.SkipTest("no multidevice")
@@ -817,6 +819,7 @@ class TestJitGraphSplit(unittest.TestCase):
@unittest.skipIf(getenv("MOCKGPU"), "MockGPU does not support parallel copies") @unittest.skipIf(getenv("MOCKGPU"), "MockGPU does not support parallel copies")
def test_jit_multidev_copy(self): def test_jit_multidev_copy(self):
if Device.DEFAULT in {"CPU", "LLVM"}: raise unittest.SkipTest("CPU/LLVM is not a valid default device for this test (zero-copies)") if Device.DEFAULT in {"CPU", "LLVM"}: raise unittest.SkipTest("CPU/LLVM is not a valid default device for this test (zero-copies)")
if Device.DEFAULT == "REMOTE": raise unittest.SkipTest("REMOTE gpu is broken")
@TinyJit @TinyJit
def f(inp): def f(inp):
@@ -62,15 +62,5 @@ class TestLinAlg(unittest.TestCase):
orthogonality_helper(Q) orthogonality_helper(Q)
reconstruction_helper([Q,R],a) reconstruction_helper([Q,R],a)
def test_newton_schulz(self):
coefficients = [(2, -1.5, 0.5), (2.0, -1.4, 0.2, 0.2)]#these params map to the sign function
sizes = [(2,2), (3,2), (2,3), (2,2,2)]
for coefs in coefficients:
for size in sizes:
a = Tensor.randn(size)
b = Tensor.newton_schulz(a, steps=20, params=coefs, eps=0.0)
# ns(A) = U @ Vt -> (U @ Vt) @ (U @ Vt)t = I
orthogonality_helper(b if size[-1] > size[-2] else b.transpose(-2, -1), tolerance=1e-1)
if __name__ == "__main__": if __name__ == "__main__":
unittest.main() unittest.main()
+64 -29
View File
@@ -2,7 +2,7 @@ import numpy as np
import unittest import unittest
from dataclasses import replace from dataclasses import replace
from tinygrad.codegen.opt.kernel import Opt, OptOps, KernelOptError, Kernel, AxisType from tinygrad.opt.kernel import Opt, OptOps, KernelOptError, Kernel, AxisType
from tinygrad.codegen.gpudims import get_grouped_dims from tinygrad.codegen.gpudims import get_grouped_dims
from tinygrad.uop.ops import UOp, Ops, GroupOp, KernelInfo from tinygrad.uop.ops import UOp, Ops, GroupOp, KernelInfo
from tinygrad.device import Device, Buffer, is_dtype_supported from tinygrad.device import Device, Buffer, is_dtype_supported
@@ -10,12 +10,9 @@ from tinygrad.shape.shapetracker import ShapeTracker
from tinygrad.shape.view import View from tinygrad.shape.view import View
from tinygrad.tensor import Tensor, _to_np_dtype from tinygrad.tensor import Tensor, _to_np_dtype
from tinygrad.engine.realize import run_schedule, lower_schedule, CompiledRunner, get_program from tinygrad.engine.realize import run_schedule, lower_schedule, CompiledRunner, get_program
from tinygrad.codegen.opt.heuristic import hand_coded_optimizations from tinygrad.opt.heuristic import hand_coded_optimizations
from tinygrad.helpers import prod, Context, getenv, CI, flatten, dedup, AMX, AMD_LLVM from tinygrad.helpers import prod, Context, getenv, CI, flatten, dedup, AMX, AMD_LLVM
from tinygrad.dtype import DType, dtypes, AddrSpace from tinygrad.dtype import DType, dtypes, AddrSpace
from tinygrad.codegen import apply_rewrites, rewrites_for_views
def push_views(ast): return apply_rewrites(ast, rewrites_for_views)
def helper_realized_ast(r:Tensor|list[Tensor]) -> tuple[UOp, list[Buffer]]: def helper_realized_ast(r:Tensor|list[Tensor]) -> tuple[UOp, list[Buffer]]:
if isinstance(r, Tensor): r = [r] if isinstance(r, Tensor): r = [r]
@@ -25,7 +22,7 @@ def helper_realized_ast(r:Tensor|list[Tensor]) -> tuple[UOp, list[Buffer]]:
# now all input buffers in s[-1] should be realized # now all input buffers in s[-1] should be realized
# create fresh buffers for the outputs # create fresh buffers for the outputs
bufs = [Buffer((x).device, x.size, x.dtype).allocate() if i < len(s[-1].ast.src) else x for i,x in enumerate(s[-1].bufs)] bufs = [Buffer((x).device, x.size, x.dtype).allocate() if i < len(s[-1].ast.src) else x for i,x in enumerate(s[-1].bufs)]
return push_views(s[-1].ast), bufs return s[-1].ast, bufs
def helper_tc_allclose(N:int, M:int, K:int, dtype_in:DType, dtype_out:DType, axis:int=0, tc_select:int=-1, tc_opt:int=0, use_tensor_cores:int=1): def helper_tc_allclose(N:int, M:int, K:int, dtype_in:DType, dtype_out:DType, axis:int=0, tc_select:int=-1, tc_opt:int=0, use_tensor_cores:int=1):
a, b = Tensor.rand(M, K, dtype=dtype_in), Tensor.rand(K, N, dtype=dtype_in) a, b = Tensor.rand(M, K, dtype=dtype_in), Tensor.rand(K, N, dtype=dtype_in)
@@ -124,7 +121,7 @@ class TestLinearizer(unittest.TestCase):
with Context(FUSE_ARANGE=1): with Context(FUSE_ARANGE=1):
sink = dataset[idxs].contiguous().kernelize().uop.base.src[1].arg.ast sink = dataset[idxs].contiguous().kernelize().uop.base.src[1].arg.ast
real_index = dataset.numpy()[idxs.numpy()].reshape(4, 256, 1, 1) real_index = dataset.numpy()[idxs.numpy()].reshape(4, 256, 1, 1)
helper_linearizer_ast(push_views(sink), [dataset, idxs], wanna_output=[real_index]) helper_linearizer_ast(sink, [dataset, idxs], wanna_output=[real_index])
def test_two_nested_range(self): def test_two_nested_range(self):
a = Tensor.randn(2, ).realize() a = Tensor.randn(2, ).realize()
@@ -217,7 +214,9 @@ class TestLinearizer(unittest.TestCase):
# these are of size 3 to avoid float4 coalesce # these are of size 3 to avoid float4 coalesce
r = a[:-1] + a[1:] r = a[:-1] + a[1:]
uops = get_program(r.schedule()[-1].ast, opts=[Opt(op=OptOps.UPCAST, axis=0, arg=0)]).uops k = Kernel(r.schedule()[-1].ast)
k.apply_opt(Opt(op=OptOps.UPCAST, axis=0, arg=0))
uops = get_program(k.get_optimized_ast(), k.opts).uops
num_loads = len([uop for uop in uops if uop.op is Ops.LOAD]) num_loads = len([uop for uop in uops if uop.op is Ops.LOAD])
assert num_loads <= 4, "more load uops than needed" assert num_loads <= 4, "more load uops than needed"
assert num_loads >= 4, "unexpected number of uops, maybe this test needs updating?" assert num_loads >= 4, "unexpected number of uops, maybe this test needs updating?"
@@ -228,7 +227,9 @@ class TestLinearizer(unittest.TestCase):
a, b = Tensor.randn(1).realize(), Tensor.randn(1).realize() a, b = Tensor.randn(1).realize(), Tensor.randn(1).realize()
r = a.expand([2]) + b.expand([2]) r = a.expand([2]) + b.expand([2])
uops = get_program(r.schedule()[-1].ast, opts=[Opt(op=OptOps.UPCAST, axis=0, arg=0)]).uops k = Kernel(r.schedule()[-1].ast)
k.apply_opt(Opt(op=OptOps.UPCAST, axis=0, arg=0))
uops = get_program(k.get_optimized_ast(), k.opts).uops
num_ops = len([uop for uop in uops if uop.op in GroupOp.ALU]) num_ops = len([uop for uop in uops if uop.op in GroupOp.ALU])
assert num_ops <= 1, "more alu uops than needed" assert num_ops <= 1, "more alu uops than needed"
@@ -237,7 +238,10 @@ class TestLinearizer(unittest.TestCase):
x, w = Tensor.randn((1,1,3)).realize(), Tensor.randn((1,1,2)).realize() x, w = Tensor.randn((1,1,3)).realize(), Tensor.randn((1,1,2)).realize()
r = Tensor.conv2d(x,w,padding=1).relu() r = Tensor.conv2d(x,w,padding=1).relu()
uops = get_program(r.schedule()[-1].ast, opts=[Opt(op=OptOps.UPCAST, axis=0, arg=0), Opt(op=OptOps.UNROLL, axis=0, arg=0)]).uops k = Kernel(r.schedule()[-1].ast)
k.apply_opt(Opt(op=OptOps.UPCAST, axis=0, arg=0))
k.apply_opt(Opt(op=OptOps.UNROLL, axis=0, arg=0))
uops = get_program(k.get_optimized_ast(), k.opts).uops
accs = [u for u in uops if u.op is Ops.DEFINE_REG] accs = [u for u in uops if u.op is Ops.DEFINE_REG]
stores = [u for u in uops if u.op is Ops.STORE] stores = [u for u in uops if u.op is Ops.STORE]
assert len(accs) == 0 # it's removed now assert len(accs) == 0 # it's removed now
@@ -249,7 +253,9 @@ class TestLinearizer(unittest.TestCase):
@unittest.skipUnless(Device.DEFAULT == "CPU", "test only for CPU") @unittest.skipUnless(Device.DEFAULT == "CPU", "test only for CPU")
def test_upcast_with_locals_cpu(self): def test_upcast_with_locals_cpu(self):
out = Tensor.ones(64,64).contiguous() @ Tensor.ones(64,64).contiguous() out = Tensor.ones(64,64).contiguous() @ Tensor.ones(64,64).contiguous()
prg = get_program(out.schedule()[-1].ast, opts=[Opt(OptOps.LOCAL, axis=0, arg=4)]).uops k = Kernel(out.schedule()[-1].ast)
k.apply_opt(Opt(OptOps.LOCAL, axis=0, arg=4))
prg = get_program(k.get_optimized_ast(), k.opts)
self.assertEqual(len(prg.src.split("for")), 5) self.assertEqual(len(prg.src.split("for")), 5)
@unittest.skipUnless(Device[Device.DEFAULT].renderer.has_local, "test requires locals") @unittest.skipUnless(Device[Device.DEFAULT].renderer.has_local, "test requires locals")
@@ -259,8 +265,10 @@ class TestLinearizer(unittest.TestCase):
def test_upcast_with_locals(self): def test_upcast_with_locals(self):
x, y = Tensor.rand(1,128), Tensor.rand(128, 128) x, y = Tensor.rand(1,128), Tensor.rand(128, 128)
r = (x@y).relu() r = (x@y).relu()
realized_ast = r.schedule()[-1].ast
opts_to_apply = [Opt(op=OptOps.GROUP, axis=0, arg=8), Opt(op=OptOps.LOCAL, axis=0, arg=4), Opt(op=OptOps.UPCAST, axis=0, arg=4)] opts_to_apply = [Opt(op=OptOps.GROUP, axis=0, arg=8), Opt(op=OptOps.LOCAL, axis=0, arg=4), Opt(op=OptOps.UPCAST, axis=0, arg=4)]
program = get_program(r.schedule()[-1].ast, opts=opts_to_apply) realized_ast = realized_ast.replace(arg=KernelInfo(opts_to_apply=tuple(opts_to_apply)))
program = get_program(realized_ast, Device[Device.DEFAULT].renderer)
stores = [u for u in program.uops if u.op is Ops.STORE and u.src[0].dtype.addrspace != AddrSpace.REG] stores = [u for u in program.uops if u.op is Ops.STORE and u.src[0].dtype.addrspace != AddrSpace.REG]
@@ -274,7 +282,10 @@ class TestLinearizer(unittest.TestCase):
def test_zero_fold(self): def test_zero_fold(self):
a, b = Tensor.randn(1).realize(), Tensor.randn(1).realize() a, b = Tensor.randn(1).realize(), Tensor.randn(1).realize()
r = Tensor.stack(a, b) r = Tensor.stack(a, b)
uops = get_program(r.schedule()[-1].ast, opts=[Opt(op=OptOps.UPCAST, axis=0, arg=0)]).uops
k = Kernel(r.schedule()[-1].ast)
k.apply_opt(Opt(op=OptOps.UPCAST, axis=0, arg=0))
uops = get_program(k.get_optimized_ast(), k.opts).uops
num_ops = len([uop for uop in uops if uop.op in GroupOp.ALU]) num_ops = len([uop for uop in uops if uop.op in GroupOp.ALU])
assert num_ops == 0, "more alu uops than needed" assert num_ops == 0, "more alu uops than needed"
@@ -284,14 +295,16 @@ class TestLinearizer(unittest.TestCase):
if is_dtype_supported(tensor_dtype) and is_dtype_supported(acc_dtype): if is_dtype_supported(tensor_dtype) and is_dtype_supported(acc_dtype):
a = Tensor([1, 2, 3], dtype=tensor_dtype).sum() a = Tensor([1, 2, 3], dtype=tensor_dtype).sum()
realized_ast = a.schedule()[-1].ast realized_ast = a.schedule()[-1].ast
program = get_program(realized_ast, opts=[]) realized_ast = realized_ast.replace(arg=KernelInfo(opts_to_apply=tuple()))
program = get_program(realized_ast, Device[Device.DEFAULT].renderer)
local = [uop for uop in program.uops if uop.op is Ops.DEFINE_REG] local = [uop for uop in program.uops if uop.op is Ops.DEFINE_REG]
assert local[0].dtype.base == acc_dtype assert local[0].dtype.base == acc_dtype
def test_arg_acc_dtype(self): def test_arg_acc_dtype(self):
def helper_arg_acc_dtype(c: Tensor, expected_dtype:DType): def helper_arg_acc_dtype(c: Tensor, expected_dtype:DType):
realized_ast = c.schedule()[-1].ast realized_ast = c.schedule()[-1].ast
program = get_program(realized_ast, opts=[]) realized_ast = realized_ast.replace(arg=KernelInfo(opts_to_apply=tuple()))
program = get_program(realized_ast, Device[Device.DEFAULT].renderer)
local = [uop for uop in program.uops if uop.op is Ops.DEFINE_REG] local = [uop for uop in program.uops if uop.op is Ops.DEFINE_REG]
self.assertEqual(local[0].dtype.base, expected_dtype) self.assertEqual(local[0].dtype.base, expected_dtype)
@@ -328,7 +341,7 @@ class TestLinearizer(unittest.TestCase):
a, b = Tensor.rand(m, k, dtype=tc.dtype_in), Tensor.rand(k, n, dtype=tc.dtype_in) a, b = Tensor.rand(m, k, dtype=tc.dtype_in), Tensor.rand(k, n, dtype=tc.dtype_in)
r = a.matmul(b, dtype=tc.dtype_out) r = a.matmul(b, dtype=tc.dtype_out)
sched = r.schedule() sched = r.schedule()
realized_ast = push_views(sched[-1].ast) realized_ast = sched[-1].ast
kernel = Kernel(realized_ast) kernel = Kernel(realized_ast)
kernel.apply_tensor_cores(1, axis=0, tc_select=-1, tc_opt=2) kernel.apply_tensor_cores(1, axis=0, tc_select=-1, tc_opt=2)
prg = get_program(kernel.get_optimized_ast(), kernel.opts) prg = get_program(kernel.get_optimized_ast(), kernel.opts)
@@ -410,7 +423,7 @@ class TestLinearizer(unittest.TestCase):
np.testing.assert_allclose(result, golden_result, atol=0.1, rtol=0.2) np.testing.assert_allclose(result, golden_result, atol=0.1, rtol=0.2)
# check that get_kernel_actions produces all 9 options # check that get_kernel_actions produces all 9 options
from tinygrad.codegen.opt.search import get_kernel_actions from tinygrad.opt.search import get_kernel_actions
tc_actions = [k for i, k in get_kernel_actions(Kernel(realized_ast), False).items() if k.applied_opts[0].op == OptOps.TC] tc_actions = [k for i, k in get_kernel_actions(Kernel(realized_ast), False).items() if k.applied_opts[0].op == OptOps.TC]
available_tc = len([x for x in Device[Device.DEFAULT].renderer.tensor_cores if x.dtype_in == tc.dtype_in and x.dtype_out == tc.dtype_out]) available_tc = len([x for x in Device[Device.DEFAULT].renderer.tensor_cores if x.dtype_in == tc.dtype_in and x.dtype_out == tc.dtype_out])
@@ -749,7 +762,11 @@ class TestFloat4(unittest.TestCase):
c = a + b c = a + b
s = c.schedule()[0] s = c.schedule()[0]
uops = get_program(s.ast, opts=[Opt(op=OptOps.UPCAST, axis=0, arg=4), Opt(op=OptOps.UPCAST, axis=0, arg=2)]).uops k = Kernel(s.ast)
k.apply_opt(Opt(op=OptOps.UPCAST, axis=0, arg=4))
k.apply_opt(Opt(op=OptOps.UPCAST, axis=0, arg=2))
uops = get_program(k.get_optimized_ast(), k.opts).uops
assert TestFloat4.count_float4(uops) == (4, 2) assert TestFloat4.count_float4(uops) == (4, 2)
@unittest.skipUnless(Device.DEFAULT in {"CPU", "LLVM"} and AMX, "Only CPU with AMX upcasts float up to size 16") @unittest.skipUnless(Device.DEFAULT in {"CPU", "LLVM"} and AMX, "Only CPU with AMX upcasts float up to size 16")
@@ -760,7 +777,10 @@ class TestFloat4(unittest.TestCase):
c = a + b c = a + b
s = c.schedule()[0] s = c.schedule()[0]
return get_program(s.ast, opts=[Opt(op=OptOps.UPCAST, axis=0, arg=4), Opt(op=OptOps.UPCAST, axis=0, arg=shift)]).uops k = Kernel(s.ast)
k.apply_opt(Opt(op=OptOps.UPCAST, axis=0, arg=4))
k.apply_opt(Opt(op=OptOps.UPCAST, axis=0, arg=shift))
return get_program(k.get_optimized_ast(), k.opts).uops
sizes = [12, 8, 16] sizes = [12, 8, 16]
shifts = [3, 2, 4] shifts = [3, 2, 4]
@@ -790,7 +810,10 @@ class TestFloat4(unittest.TestCase):
c = a + b c = a + b
s = c.schedule()[0] s = c.schedule()[0]
uops = get_program(s.ast, opts=[Opt(op=OptOps.UPCAST, axis=1, arg=4), Opt(op=OptOps.UPCAST, axis=1, arg=2)]).uops k = Kernel(s.ast)
k.apply_opt(Opt(op=OptOps.UPCAST, axis=1, arg=4))
k.apply_opt(Opt(op=OptOps.UPCAST, axis=1, arg=2))
uops = get_program(k.get_optimized_ast(), k.opts).uops
assert TestFloat4.count_float4(uops) == (0, 2) assert TestFloat4.count_float4(uops) == (0, 2)
@@ -802,7 +825,10 @@ class TestFloat4(unittest.TestCase):
c = a + b c = a + b
s = c.schedule()[0] s = c.schedule()[0]
return get_program(s.ast, opts=[Opt(op=OptOps.UPCAST, axis=1, arg=4), Opt(op=OptOps.UPCAST, axis=1, arg=shift)]).uops k = Kernel(s.ast)
k.shift_to(1, 4, AxisType.UPCAST) # manual trigger float4 dim
k.shift_to(1, shift, AxisType.UPCAST, insert_at=k.shape_len-1)
return get_program(k.get_optimized_ast(), k.opts).uops
sizes = [13, 9, 17] sizes = [13, 9, 17]
shifts = [3, 2, 4] shifts = [3, 2, 4]
@@ -820,7 +846,9 @@ class TestFloat4(unittest.TestCase):
# float4 should be emitted (the reduce axis of size 4 is the float4 axis here) # float4 should be emitted (the reduce axis of size 4 is the float4 axis here)
s = c.schedule()[0] s = c.schedule()[0]
uops = get_program(s.ast, opts=[Opt(op=OptOps.UNROLL, axis=0, arg=4)]).uops k = Kernel(s.ast)
k.apply_opt(Opt(op=OptOps.UNROLL, axis=0, arg=4))
uops = get_program(k.get_optimized_ast(), k.opts).uops
assert TestFloat4.count_float4(uops) == (0, 0) assert TestFloat4.count_float4(uops) == (0, 0)
@@ -834,7 +862,10 @@ class TestFloat4(unittest.TestCase):
# UPDATE: now we do this fusion # UPDATE: now we do this fusion
s = c.schedule()[0] s = c.schedule()[0]
uops = get_program(s.ast, opts=[Opt(op=OptOps.UPCAST, axis=0, arg=0), Opt(op=OptOps.UNROLL, axis=0, arg=0)]).uops k = Kernel(s.ast)
k.apply_opt(Opt(op=OptOps.UPCAST, axis=0, arg=0))
k.apply_opt(Opt(op=OptOps.UNROLL, axis=0, arg=0))
uops = get_program(k.get_optimized_ast(), k.opts).uops
assert TestFloat4.count_float4(uops) in {(0,1), (1,1)} assert TestFloat4.count_float4(uops) in {(0,1), (1,1)}
@@ -847,7 +878,9 @@ class TestFloat4(unittest.TestCase):
# since the top axis is not contiguous. # since the top axis is not contiguous.
s = c.schedule()[0] s = c.schedule()[0]
uops = get_program(s.ast, opts=[Opt(op=OptOps.UPCAST, axis=0, arg=4)]).uops k = Kernel(s.ast)
k.apply_opt(Opt(op=OptOps.UPCAST, axis=0, arg=4))
uops = get_program(k.get_optimized_ast(), k.opts).uops
assert TestFloat4.count_float4(uops) == (0, 1) assert TestFloat4.count_float4(uops) == (0, 1)
@@ -859,7 +892,9 @@ class TestFloat4(unittest.TestCase):
# should float4 b but not a # should float4 b but not a
s = c.schedule()[0] s = c.schedule()[0]
uops = get_program(s.ast, opts=[Opt(op=OptOps.UPCAST, axis=0, arg=4)]).uops k = Kernel(s.ast)
k.apply_opt(Opt(op=OptOps.UPCAST, axis=0, arg=4))
uops = get_program(k.get_optimized_ast(), k.opts).uops
assert TestFloat4.count_float4(uops) == (1, 1) assert TestFloat4.count_float4(uops) == (1, 1)
@@ -948,7 +983,7 @@ class TestHandCodedOpts(unittest.TestCase):
layer_2 = Tensor.cat(layer_1.unsqueeze(0), Tensor.empty(6, 20)) layer_2 = Tensor.cat(layer_1.unsqueeze(0), Tensor.empty(6, 20))
s = layer_2.schedule()[-1] s = layer_2.schedule()[-1]
k = Kernel(push_views(s.ast)) k = Kernel(s.ast)
k.apply_opts(hand_coded_optimizations(k)) k.apply_opts(hand_coded_optimizations(k))
assert len(k.bufs) == 6 # make sure all ops are done in one kernel assert len(k.bufs) == 6 # make sure all ops are done in one kernel
# masked upcast should upcast masked axis of size 7 # masked upcast should upcast masked axis of size 7
@@ -961,7 +996,7 @@ class TestHandCodedOpts(unittest.TestCase):
monster = Tensor.stack(*[Tensor.stack(*[Tensor.empty(16) for _ in range(6)]) for _ in range(6)]) monster = Tensor.stack(*[Tensor.stack(*[Tensor.empty(16) for _ in range(6)]) for _ in range(6)])
s = monster.schedule()[-1] s = monster.schedule()[-1]
k = Kernel(push_views(s.ast)) k = Kernel(s.ast)
k.apply_opts(hand_coded_optimizations(k)) k.apply_opts(hand_coded_optimizations(k))
assert len(k.bufs) == 37 # make sure all ops are done in one kernel assert len(k.bufs) == 37 # make sure all ops are done in one kernel
# should upcast the two Tensor.stacks # should upcast the two Tensor.stacks
@@ -977,7 +1012,7 @@ class TestHandCodedOpts(unittest.TestCase):
wino_schedule = out.schedule() wino_schedule = out.schedule()
# collect upcasts of tile transform kernels # collect upcasts of tile transform kernels
for i, si in enumerate(wino_schedule): for i, si in enumerate(wino_schedule):
k = Kernel(push_views(si.ast)) k = Kernel(si.ast)
k.apply_opts(hand_coded_optimizations(k)) k.apply_opts(hand_coded_optimizations(k))
if k.reduceop is not None: continue # not a tile transform kernel (there is a gemm reduce kernel) if k.reduceop is not None: continue # not a tile transform kernel (there is a gemm reduce kernel)
if len(k.bufs) < 22: continue # not a tile transform kernel (there's a permute kernel at the end) if len(k.bufs) < 22: continue # not a tile transform kernel (there's a permute kernel at the end)
@@ -989,7 +1024,7 @@ class TestHandCodedOpts(unittest.TestCase):
backward_schedule = Tensor.schedule(x.grad, w.grad) backward_schedule = Tensor.schedule(x.grad, w.grad)
for si in backward_schedule: for si in backward_schedule:
k = Kernel(push_views(si.ast)) k = Kernel(si.ast)
k.apply_opts(hand_coded_optimizations(k)) k.apply_opts(hand_coded_optimizations(k))
if len(k.bufs) < 20: continue # not a tile transform kernel if len(k.bufs) < 20: continue # not a tile transform kernel
# heuristic number to make sure that at least some upcasts but not too many upcasts are being done # heuristic number to make sure that at least some upcasts but not too many upcasts are being done
+2 -2
View File
@@ -8,8 +8,8 @@ from tinygrad.device import is_dtype_supported
from tinygrad.uop.ops import UOp, Ops from tinygrad.uop.ops import UOp, Ops
from tinygrad.helpers import getenv from tinygrad.helpers import getenv
from tinygrad.shape.shapetracker import ShapeTracker, View from tinygrad.shape.shapetracker import ShapeTracker, View
from tinygrad.codegen.opt.search import Opt, OptOps from tinygrad.opt.search import Opt, OptOps
from tinygrad.codegen.opt.kernel import Kernel from tinygrad.opt.kernel import Kernel
from tinygrad.engine.realize import get_program from tinygrad.engine.realize import get_program
class TestLinearizerDumb(unittest.TestCase): class TestLinearizerDumb(unittest.TestCase):
+2 -2
View File
@@ -1,8 +1,8 @@
# ruff: noqa: E501 # ruff: noqa: E501
import unittest import unittest
from tinygrad import dtypes from tinygrad import dtypes
from tinygrad.codegen.opt.kernel import Kernel from tinygrad.opt.kernel import Kernel
from tinygrad.codegen.opt.search import Opt, OptOps, bufs_from_lin from tinygrad.opt.search import Opt, OptOps, bufs_from_lin
from extra.optimization.helpers import time_linearizer from extra.optimization.helpers import time_linearizer
# stuff needed to unpack a kernel # stuff needed to unpack a kernel
+4 -4
View File
@@ -373,11 +373,11 @@ class TestMultiTensor(unittest.TestCase):
np.testing.assert_allclose(y.numpy(), y_shard.numpy(), atol=1e-6, rtol=1e-6) np.testing.assert_allclose(y.numpy(), y_shard.numpy(), atol=1e-6, rtol=1e-6)
# NOTE: this is failing on LLVM CI, no idea why. Works locally. # NOTE: this is failing on LLVM CI, no idea why. Works locally.
@unittest.skipIf(CI and REAL_DEV in ("CUDA", "NV", "LLVM", "CPU", "AMD"), "slow, and flaky on LLVM/CPU") @unittest.skipIf(CI and REAL_DEV in ("CUDA", "NV", "LLVM", "CPU"), "slow, and flaky on LLVM/CPU")
def test_data_parallel_resnet(self): def test_data_parallel_resnet(self):
from extra.models.resnet import ResNet18 from extra.models.resnet import ResNet18
fake_image = Tensor.rand((2, 3, 224//16, 224//16)) fake_image = Tensor.rand((2, 3, 224//8, 224//8))
fake_image_sharded = fake_image.shard(devices_2, axis=0) fake_image_sharded = fake_image.shard(devices_2, axis=0)
m = ResNet18() m = ResNet18()
m.load_from_pretrained() m.load_from_pretrained()
@@ -409,10 +409,10 @@ class TestMultiTensor(unittest.TestCase):
# sometimes there is zeros in these grads... why? # sometimes there is zeros in these grads... why?
np.testing.assert_allclose(grad, shard_grad, atol=1e-5, rtol=1e-5) np.testing.assert_allclose(grad, shard_grad, atol=1e-5, rtol=1e-5)
@unittest.skipIf(CI and REAL_DEV in ("CUDA", "NV", "LLVM", "CPU", "AMD"), "slow, and flaky on LLVM/CPU") @unittest.skipIf(CI and REAL_DEV in ("CUDA", "NV", "LLVM", "CPU"), "slow, and flaky on LLVM/CPU")
def test_data_parallel_resnet_train_step(self): def test_data_parallel_resnet_train_step(self):
from extra.models.resnet import ResNet18 from extra.models.resnet import ResNet18
fake_image = Tensor.rand((2, 3, 224//16, 224//16)) fake_image = Tensor.rand((2, 3, 224//8, 224//8))
labels = Tensor.randint(2, low=0, high=1000) labels = Tensor.randint(2, low=0, high=1000)
m = ResNet18() m = ResNet18()
self._test_model_train_step(m, fake_image, labels) self._test_model_train_step(m, fake_image, labels)
+87
View File
@@ -0,0 +1,87 @@
#!/usr/bin/env python
import time
import unittest
import torch
from tinygrad import Tensor, Device
from tinygrad.helpers import Profiling, CI
@unittest.skipIf(CI and Device.DEFAULT in {"CUDA", "NV"}, "slow")
class TestConvSpeed(unittest.TestCase):
def test_mnist(self):
# https://keras.io/examples/vision/mnist_convnet/
conv = 3
inter_chan, out_chan = 32, 64
# ****** torch baseline *******
torch.backends.mkldnn.enabled = False
conv = 3
inter_chan, out_chan = 32, 64
c1 = torch.randn(inter_chan,1,conv,conv, requires_grad=True)
c2 = torch.randn(out_chan,inter_chan,conv,conv, requires_grad=True)
l1 = torch.randn(out_chan*5*5, 10, requires_grad=True)
c2d = torch.nn.functional.conv2d
mp = torch.nn.MaxPool2d((2,2))
lsm = torch.nn.LogSoftmax(dim=1)
cnt = 5
fpt, bpt = 0.0, 0.0
for i in range(cnt):
et0 = time.time()
x = torch.randn(128, 1, 28, 28, requires_grad=True)
x = mp(c2d(x,c1).relu())
x = mp(c2d(x,c2).relu())
x = x.reshape(x.shape[0], -1)
out = lsm(x.matmul(l1))
out = out.mean()
et1 = time.time()
out.backward()
et2 = time.time()
fpt += (et1-et0)
bpt += (et2-et1)
fpt_baseline = (fpt*1000/cnt)
bpt_baseline = (bpt*1000/cnt)
print("torch forward pass: %.3f ms" % fpt_baseline)
print("torch backward pass: %.3f ms" % bpt_baseline)
# ****** tinygrad compare *******
c1 = Tensor(c1.detach().numpy(), requires_grad=True)
c2 = Tensor(c2.detach().numpy(), requires_grad=True)
l1 = Tensor(l1.detach().numpy(), requires_grad=True)
cnt = 5
fpt, bpt = 0.0, 0.0
for i in range(1+cnt):
et0 = time.time()
x = Tensor.randn(128, 1, 28, 28)
x = x.conv2d(c1).relu().avg_pool2d()
x = x.conv2d(c2).relu().max_pool2d()
x = x.reshape(shape=(x.shape[0], -1))
out = x.dot(l1).log_softmax()
out = out.mean()
out.backward() # NOTE: we have to now compute this here, but it doesn't realize
out.realize()
et1 = time.time()
[x.grad.realize() for x in [c1, c2, l1]]
et2 = time.time()
if i == 0:
pr = Profiling(sort='time', frac=0.2)
pr.__enter__()
else:
fpt += (et1-et0)
bpt += (et2-et1)
pr.__exit__()
fpt = (fpt*1000/cnt)
bpt = (bpt*1000/cnt)
print("forward pass: %.3f ms, %.2fx off baseline %.3f ms" % (fpt, fpt/fpt_baseline, fpt_baseline))
print("backward pass: %.3f ms, %.2fx off baseline %.3f ms" % (bpt, bpt/bpt_baseline, bpt_baseline))
if __name__ == '__main__':
unittest.main()

Some files were not shown because too many files have changed in this diff Show More