Skip to content

Commit 0b9c65b

Browse files
Merge pull request #19 from knights-analytics/gpu-support
Gpu support
2 parents af89cb0 + cc1ab08 commit 0b9c65b

17 files changed

Lines changed: 407 additions & 145 deletions

.github/workflows/release.yaml

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,11 @@ permissions:
1111

1212
jobs:
1313
test:
14-
name: Run test suite
15-
runs-on: ubuntu-latest
16-
steps:
14+
name: Run test suite
15+
runs-on: ubuntu-latest
16+
env:
17+
CI: true
18+
steps:
1719
- name: Set up Go
1820
uses: actions/setup-go@v2
1921
with:
@@ -37,12 +39,16 @@ jobs:
3739
path: ./artifacts/libtokenizers.a
3840
- uses: actions/upload-artifact@v4
3941
with:
40-
name: onnxruntime.so
41-
path: ./artifacts/onnxruntime.so
42+
name: onnxruntime-linux-x64.so
43+
path: ./artifacts/onnxruntime-linux-x64.so
44+
- uses: actions/upload-artifact@v4
45+
with:
46+
name: onnxruntime-linux-x64-gpu
47+
path: ./artifacts/onnxruntime-linux-x64-gpu
4248
- uses: actions/upload-artifact@v4
4349
with:
44-
name: hugot-cli-linux-amd64
45-
path: ./artifacts/hugot-cli-linux-amd64
50+
name: hugot-cli-linux-x64
51+
path: ./artifacts/hugot-cli-linux-x64
4652
- name: Publish Test Report
4753
uses: mikepenz/action-junit-report@v4
4854
if: success() || failure()
@@ -63,16 +69,20 @@ jobs:
6369
path: .
6470
- uses: actions/download-artifact@v4
6571
with:
66-
name: onnxruntime.so
72+
name: onnxruntime-linux-x64.so
73+
path: .
74+
- uses: actions/download-artifact@v4
75+
with:
76+
name: hugot-cli-linux-x64
6777
path: .
6878
- uses: actions/download-artifact@v4
6979
with:
70-
name: hugot-cli-linux-amd64
80+
name: onnxruntime-linux-x64-gpu
7181
path: .
7282
- name: Display structure of downloaded files
7383
run: ls -R
7484
- uses: ncipollo/release-action@v1
7585
with:
76-
artifacts: "libtokenizers.a, onnxruntime.so, hugot-cli-linux-amd64"
86+
artifacts: "libtokenizers.a, onnxruntime-linux-x64.so, onnxruntime-linux-x64-gpu, hugot-cli-linux-x64"
7787
generateReleaseNotes: true
7888
skipIfReleaseExists: true

.github/workflows/test.yaml

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ jobs:
1010
test:
1111
name: Run test suite
1212
runs-on: ubuntu-latest
13+
env:
14+
CI: true
1315
steps:
1416
- name: Set up Go
1517
uses: actions/setup-go@v2
@@ -34,12 +36,16 @@ jobs:
3436
path: ./artifacts/libtokenizers.a
3537
- uses: actions/upload-artifact@v4
3638
with:
37-
name: onnxruntime.so
38-
path: ./artifacts/onnxruntime.so
39+
name: onnxruntime-linux-x64.so
40+
path: ./artifacts/onnxruntime-linux-x64.so
3941
- uses: actions/upload-artifact@v4
4042
with:
41-
name: hugot-cli-linux-amd64
42-
path: ./artifacts/hugot-cli-linux-amd64
43+
name: onnxruntime-linux-x64-gpu
44+
path: ./artifacts/onnxruntime-linux-x64-gpu
45+
- uses: actions/upload-artifact@v4
46+
with:
47+
name: hugot-cli-linux-x64
48+
path: ./artifacts/hugot-cli-linux-x64
4349
- name: Publish Test Report
4450
uses: mikepenz/action-junit-report@v4
4551
if: success() || failure()

Dockerfile

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
ARG GO_VERSION=1.22.2
22
ARG RUST_VERSION=1.77
3-
ARG ONNXRUNTIME_VERSION=1.17.1
3+
ARG ONNXRUNTIME_VERSION=1.17.3
4+
ARG CUDA_VERSION=12.4
45

56
#--- rust build of tokenizer ---
67

@@ -12,40 +13,54 @@ RUN git clone https://github.com/knights-analytics/tokenizers -b main && \
1213

1314
#--- build and test layer ---
1415

15-
FROM public.ecr.aws/amazonlinux/amazonlinux:2023 AS building
16+
FROM public.ecr.aws/amazonlinux/amazonlinux:2023 AS hugot-build
1617
ARG GO_VERSION
1718
ARG ONNXRUNTIME_VERSION
1819

1920
RUN dnf -y install gcc jq bash tar xz gzip glibc-static libstdc++ wget zip git && \
2021
ln -s /usr/lib64/libstdc++.so.6 /usr/lib64/libstdc++.so && \
2122
dnf install -y 'dnf-command(config-manager)' && \
22-
dnf config-manager \
23-
--add-repo https://download.fedoraproject.org/pub/fedora/linux/releases/39/Everything/x86_64/os/ && \
23+
dnf config-manager --add-repo https://download.fedoraproject.org/pub/fedora/linux/releases/39/Everything/x86_64/os/ && \
24+
# from fedora
25+
dnf config-manager --add-repo https://developer.download.nvidia.com/compute/cuda/repos/fedora39/x86_64/cuda-fedora39.repo && \
26+
dnf install -y cuda-cudart-12-4 libcublas-12-4 libcurand-12-4 libcufft-12-4 && \
27+
# from rhel
28+
dnf config-manager --add-repo https://developer.download.nvidia.com/compute/cuda/repos/rhel9/x86_64/cuda-rhel9.repo && \
29+
dnf install -y libcudnn8 && \
2430
dnf clean all
2531

32+
# go
2633
RUN curl -LO https://golang.org/dl/go${GO_VERSION}.linux-amd64.tar.gz && \
2734
tar -C /usr/local -xzf go${GO_VERSION}.linux-amd64.tar.gz && \
2835
rm go${GO_VERSION}.linux-amd64.tar.gz
2936
ENV PATH="$PATH:/usr/local/go/bin"
3037

38+
# tokenizer
3139
COPY --from=tokenizer /tokenizers/target/release/libtokenizers.a /usr/lib/libtokenizers.a
40+
41+
# onnxruntime cpu and gpu
3242
RUN curl -LO https://github.com/microsoft/onnxruntime/releases/download/v${ONNXRUNTIME_VERSION}/onnxruntime-linux-x64-${ONNXRUNTIME_VERSION}.tgz && \
3343
tar -xzf onnxruntime-linux-x64-${ONNXRUNTIME_VERSION}.tgz && \
34-
mv ./onnxruntime-linux-x64-${ONNXRUNTIME_VERSION}/lib/libonnxruntime.so.${ONNXRUNTIME_VERSION} /usr/lib64/onnxruntime.so
44+
mv ./onnxruntime-linux-x64-${ONNXRUNTIME_VERSION}/lib/libonnxruntime.so.${ONNXRUNTIME_VERSION} /usr/lib64/onnxruntime.so && \
45+
curl -LO https://github.com/microsoft/onnxruntime/releases/download/v${ONNXRUNTIME_VERSION}/onnxruntime-linux-x64-gpu-cuda12-${ONNXRUNTIME_VERSION}.tgz && \
46+
tar -xzf onnxruntime-linux-x64-gpu-cuda12-${ONNXRUNTIME_VERSION}.tgz && \
47+
mv ./onnxruntime-linux-x64-gpu-${ONNXRUNTIME_VERSION}/lib /usr/lib64/onnxruntime-gpu
3548

49+
# build gotestsum and test2json
3650
RUN GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o test2json -ldflags="-s -w" cmd/test2json && mv test2json /usr/local/bin/test2json && \
3751
curl -LO https://github.com/gotestyourself/gotestsum/releases/download/v1.11.0/gotestsum_1.11.0_linux_amd64.tar.gz && \
3852
tar -xzf gotestsum_1.11.0_linux_amd64.tar.gz --directory /usr/local/bin
3953

40-
# build cli
54+
# build cli binary
4155
COPY . /build
4256
WORKDIR /build
4357
RUN cd ./cmd && CGO_ENABLED=1 GOOS=linux GOARCH=amd64 go build -a -o ./target main.go
4458

4559
# NON-PRIVILEDGED USER
4660
# create non-priviledged testuser with id: 1000
47-
RUN dnf install --disablerepo=* --enablerepo=amazonlinux --allowerasing -y dirmngr && dnf clean all
48-
RUN useradd -u 1000 -m testuser && chown -R testuser:testuser /build
61+
RUN dnf install --disablerepo=* --enablerepo=amazonlinux --allowerasing -y dirmngr sudo which && dnf clean all
62+
RUN useradd -u 1000 -m testuser && chown -R testuser:testuser /build && usermod -a -G wheel testuser
63+
RUN echo "testuser ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers.d/testuser
4964

5065
# ENTRYPOINT
5166
COPY ./scripts/entrypoint.sh /entrypoint.sh
@@ -54,10 +69,10 @@ RUN sed -i 's/\r//g' /entrypoint.sh
5469
RUN chmod +x /entrypoint.sh
5570
ENTRYPOINT ["/entrypoint.sh"]
5671

57-
#--- artifacts layer
58-
72+
# artifacts layer
5973
FROM scratch AS artifacts
6074

61-
COPY --from=building /usr/lib64/onnxruntime.so onnxruntime.so
62-
COPY --from=building /usr/lib/libtokenizers.a libtokenizers.a
63-
COPY --from=building /build/cmd/target /hugot-cli-linux-amd64
75+
COPY --from=hugot-build /usr/lib64/onnxruntime.so onnxruntime-linux-x64.so
76+
COPY --from=hugot-build /usr/lib64/onnxruntime-gpu onnxruntime-linux-x64-gpu
77+
COPY --from=hugot-build /usr/lib/libtokenizers.a libtokenizers.a
78+
COPY --from=hugot-build /build/cmd/target /hugot-cli-linux-x64

README.md

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ The goal of this library is to provide an easy, scalable, and hassle-free way to
1212
2. Hassle-free and performant production use: we exclusively support onnx exports of huggingface models. Pytorch transformer models that don't have an onnx version can be easily exported to onnx via [huggingface optimum](https://huggingface.co/docs/optimum/index), and used with the library
1313
3. Run on your hardware: this library is for those who want to run transformer models tightly coupled with their go applications, without the performance drawbacks of having to hit a rest API, or the hassle of setting up and maintaining e.g. a python RPC service that talks to go.
1414

15+
We support inference on CPU and on all accelerators supported by ONNXRuntime. Note, however, that currently only CPU and GPU inference on nvidia GPU (with cuda) are tested (see below).
16+
1517
## Why
1618

1719
Developing and fine-tuning transformer models with the huggingface python library is a great experience, but if your production stack is golang-based being able to reliably deploy and scale the resulting pytorch models can be challenging and require quite some setup. This library aims to allow you to just lift-and-shift your python model and use the same huggingface pipelines you use for development for inference in a go application.
@@ -20,7 +22,7 @@ Developing and fine-tuning transformer models with the huggingface python librar
2022

2123
For the golang developer or ML engineer who wants to run transformer piplines on their own hardware, tightly coupled with their own application.
2224

23-
## What is already there
25+
## Implemented pipelines
2426

2527
Currently, we have implementations for the following transfomer pipelines:
2628

@@ -32,11 +34,34 @@ Implementations for additional pipelines will follow. We also very gladly accept
3234

3335
Hugot can be used both as a library and as a command-line application. See below for usage instructions.
3436

37+
## Hardware acceleration 🚀
38+
39+
Hugot now also supports the following accelerator backends for your inference:
40+
- CUDA (tested). See below for setup instructions.
41+
- TensorRT (untested)
42+
- DirectML (untested)
43+
- CoreML (untested)
44+
- OpenVINO (untested)
45+
46+
Please help us out by testing the untested options above and providing feedback, good or bad!
47+
48+
To use Hugot with nvidia gpu acceleration, you need to have the following:
49+
50+
- The cuda gpu version of onnxruntime on the machine/docker container. You can see how we get that by looking at the [Dockerfile](./Dockerfile). You can also get the onnxruntime libraries that we use for testing from the release. Just download the gpu .so libraries and put them in /usr/lib64.
51+
- the nvidia driver for your graphics card
52+
- the required cuda libraries installed on your system that are compatible with the onnxruntime gpu version you use. See [here](https://onnxruntime.ai/docs/execution-providers/CUDA-ExecutionProvider.html). For instance, for onnxruntime-gpu 17.3, we need CUDA 12.x (any minor version should be compatible) and cuDNN 8.9.2.26.
53+
54+
On the last point above, you can install CUDA 12.x by installing the full cuda toolkit, but that's quite a big package. In our testing on awslinux/fedora, we have been able to limit the libraries needed to run hugot with nvidia gpu acceleration to just these:
55+
56+
- cuda-cudart-12-4 libcublas-12-4 libcurand-12-4 libcufft-12-4 (from fedora repo)
57+
- libcudnn8 (from RHEL repo, for cuDNN)
58+
59+
On different distros (e.g. Ubuntu), you should be able to install the equivalent packages and gpu inference should work.
60+
3561
## Limitations
3662

3763
Apart from the fact that only the aforementioned pipelines are currently implemented, the current limitations are:
38-
- the library and cli are only tested on amd64-linux
39-
- only CPU inference is supported
64+
- the library and cli are only built/tested on amd64-linux
4065

4166
Pipelines are also tested on specifically NLP use cases. In particular, we use the following models for testing:
4267
- feature extraction: all-MiniLM-L6-v2
@@ -196,6 +221,8 @@ session, err := hugot.NewSession(
196221

197222
InterOpNumThreads and IntraOpNumThreads constricts each goroutine's call to a single core, greatly reducing locking and cache penalties. Disabling CpuMemArena and MemPattern skips pre-allocation of some memory structures, increasing latency, but also throughput efficiency.
198223

224+
For GPU the config above also applies. We are still testing the optimum GPU configuration, whether it is better to run in parallel or with a single thread, and what size of input batch is fastest.
225+
199226
## Contributing
200227

201228
### Development environment

cmd/main.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,12 @@ import (
1313
"strings"
1414
"sync"
1515

16+
"github.com/mattn/go-isatty"
17+
"github.com/urfave/cli/v2"
18+
1619
"github.com/knights-analytics/hugot"
1720
"github.com/knights-analytics/hugot/pipelines"
1821
util "github.com/knights-analytics/hugot/utils"
19-
"github.com/mattn/go-isatty"
20-
"github.com/urfave/cli/v2"
2122
)
2223

2324
var modelPath string

cmd/main_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@ package main
22

33
import (
44
"context"
5+
_ "embed"
56
"fmt"
67
"os"
78
"path"
89
"testing"
910

10-
_ "embed"
11+
"github.com/urfave/cli/v2"
1112

1213
util "github.com/knights-analytics/hugot/utils"
13-
"github.com/urfave/cli/v2"
1414
)
1515

1616
//go:embed testData/textClassification.jsonl

compose-dev.yaml

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,14 @@ services:
44
build:
55
context: .
66
dockerfile: ./Dockerfile
7-
target: building
7+
target: hugot-build
88
volumes:
99
- $src_dir:/home/testuser/repositories/hugot
10-
entrypoint: ["tail", "-f", "/dev/null"]
10+
entrypoint: ["tail", "-f", "/dev/null"]
11+
deploy:
12+
resources:
13+
reservations:
14+
devices:
15+
- driver: nvidia
16+
count: 1
17+
capabilities: [gpu]

compose-test.yaml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,18 @@ services:
55
build:
66
context: .
77
dockerfile: ./Dockerfile
8-
target: building
8+
target: hugot-build
99
volumes:
1010
- $test_folder:/test
1111
- $test_folder/../scripts/run-unit-tests-container.sh:/run-unit-tests-container.sh
1212
environment:
1313
- HOST_UID=$host_uid
14+
- CI=$CI
1415
command: /run-unit-tests-container.sh
16+
# deploy:
17+
# resources:
18+
# reservations:
19+
# devices:
20+
# - driver: nvidia
21+
# count: 1
22+
# capabilities: [gpu]

downloader.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ import (
1414
"time"
1515

1616
hfd "github.com/bodaay/HuggingFaceModelDownloader/hfdownloader"
17+
18+
util "github.com/knights-analytics/hugot/utils"
1719
)
1820

1921
// DownloadOptions is a struct of options that can be passed to DownloadModel
@@ -138,3 +140,26 @@ func checkURL(client *http.Client, url string, authToken string) (bool, bool, er
138140
}
139141
return tokenizerFound, onnxFound, nil
140142
}
143+
144+
func downloadModelIfNotExists(session *Session, modelName string, destination string) string {
145+
146+
modelNameFS := modelName
147+
if strings.Contains(modelNameFS, ":") {
148+
modelNameFS = strings.Split(modelName, ":")[0]
149+
}
150+
modelNameFS = path.Join(destination, strings.Replace(modelNameFS, "/", "_", -1))
151+
152+
fullModelPath := path.Join(destination, modelNameFS)
153+
exists, err := util.FileSystem.Exists(context.Background(), fullModelPath)
154+
if err != nil {
155+
panic(err)
156+
}
157+
if exists {
158+
return fullModelPath
159+
}
160+
fullModelPath, err = session.DownloadModel(modelName, destination, NewDownloadOptions())
161+
if err != nil {
162+
panic(err)
163+
}
164+
return fullModelPath
165+
}

go.mod

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,28 +2,27 @@ module github.com/knights-analytics/hugot
22

33
go 1.22
44

5+
replace github.com/viant/afsc => github.com/knights-analytics/afsc v0.0.0-20240419150436-7b7def176954
6+
57
require (
68
github.com/bodaay/HuggingFaceModelDownloader v0.0.0-20240307153905-2f38356a6d6c
79
github.com/json-iterator/go v1.1.12
8-
github.com/knights-analytics/tokenizers v0.10.0
10+
github.com/knights-analytics/tokenizers v0.12.0
911
github.com/mattn/go-isatty v0.0.20
1012
github.com/stretchr/testify v1.9.0
1113
github.com/urfave/cli/v2 v2.27.1
12-
github.com/viant/afs v1.25.0
13-
github.com/viant/afsc v1.9.1
14+
github.com/viant/afs v1.25.1
15+
github.com/viant/afsc v1.9.2
1416
github.com/yalue/onnxruntime_go v1.9.0
1517
)
1618

1719
require (
18-
cloud.google.com/go v0.112.2 // indirect
19-
cloud.google.com/go/storage v1.40.0 // indirect
20-
github.com/aws/aws-sdk-go v1.51.21 // indirect
20+
github.com/aws/aws-sdk-go v1.51.28 // indirect
2121
github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect
2222
github.com/davecgh/go-spew v1.1.1 // indirect
2323
github.com/fatih/color v1.16.0 // indirect
2424
github.com/go-errors/errors v1.5.1 // indirect
2525
github.com/jmespath/go-jmespath v0.4.0 // indirect
26-
github.com/kr/text v0.2.0 // indirect
2726
github.com/mattn/go-colorable v0.1.13 // indirect
2827
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
2928
github.com/modern-go/reflect2 v1.0.2 // indirect
@@ -32,14 +31,6 @@ require (
3231
github.com/russross/blackfriday/v2 v2.1.0 // indirect
3332
github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 // indirect
3433
golang.org/x/crypto v0.22.0 // indirect
35-
golang.org/x/net v0.24.0 // indirect
36-
golang.org/x/oauth2 v0.19.0 // indirect
37-
golang.org/x/sync v0.7.0 // indirect
3834
golang.org/x/sys v0.19.0 // indirect
39-
google.golang.org/api v0.172.0 // indirect
40-
google.golang.org/genproto v0.0.0-20240401170217-c3f982113cda // indirect
41-
google.golang.org/genproto/googleapis/api v0.0.0-20240401170217-c3f982113cda // indirect
42-
google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda // indirect
43-
google.golang.org/grpc v1.63.0 // indirect
4435
gopkg.in/yaml.v3 v3.0.1 // indirect
4536
)

0 commit comments

Comments
 (0)