vollo-rt 27.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- _vollo_rt.py +11 -0
- vollo_rt/__init__.py +590 -0
- vollo_rt-27.0.0.dist-info/EULA.md +101 -0
- vollo_rt-27.0.0.dist-info/METADATA +9 -0
- vollo_rt-27.0.0.dist-info/RECORD +7 -0
- vollo_rt-27.0.0.dist-info/WHEEL +5 -0
- vollo_rt-27.0.0.dist-info/top_level.txt +2 -0
_vollo_rt.py
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# auto-generated file
|
|
2
|
+
import _cffi_backend
|
|
3
|
+
|
|
4
|
+
ffi = _cffi_backend.FFI('_vollo_rt',
|
|
5
|
+
_version = 0x2601,
|
|
6
|
+
_types = b'\x00\x00\x05\x0D\x00\x00\x04\x03\x00\x00\x00\x0F\x00\x00\x05\x0D\x00\x00\x78\x03\x00\x00\x6D\x03\x00\x00\x00\x0F\x00\x00\x05\x0D\x00\x00\x04\x11\x00\x00\x0E\x03\x00\x00\x77\x03\x00\x00\x00\x0F\x00\x00\x05\x0D\x00\x00\x04\x11\x00\x00\x1C\x01\x00\x00\x00\x0F\x00\x00\x05\x0D\x00\x00\x04\x11\x00\x00\x1C\x01\x00\x00\x01\x01\x00\x00\x00\x0F\x00\x00\x05\x0D\x00\x00\x04\x11\x00\x00\x1C\x01\x00\x00\x18\x01\x00\x00\x70\x03\x00\x00\x6F\x03\x00\x00\x00\x0F\x00\x00\x05\x0D\x00\x00\x04\x11\x00\x00\x1C\x01\x00\x00\x18\x01\x00\x00\x3A\x03\x00\x00\x75\x03\x00\x00\x00\x0F\x00\x00\x05\x0D\x00\x00\x04\x11\x00\x00\x1C\x01\x00\x00\x18\x01\x00\x00\x30\x03\x00\x00\x3F\x03\x00\x00\x27\x11\x00\x00\x04\x03\x00\x00\x00\x0F\x00\x00\x05\x0D\x00\x00\x04\x11\x00\x00\x1C\x01\x00\x00\x18\x01\x00\x00\x16\x01\x00\x00\x73\x03\x00\x00\x2A\x11\x00\x00\x00\x0F\x00\x00\x05\x0D\x00\x00\x04\x11\x00\x00\x1C\x01\x00\x00\x18\x01\x00\x00\x16\x01\x00\x00\x27\x11\x00\x00\x76\x03\x00\x00\x21\x11\x00\x00\x00\x0F\x00\x00\x05\x0D\x00\x00\x04\x11\x00\x00\x78\x03\x00\x00\x1C\x01\x00\x00\x00\x0F\x00\x00\x05\x0D\x00\x00\x00\x0F\x00\x00\x72\x0D\x00\x00\x04\x11\x00\x00\x1C\x01\x00\x00\x1C\x01\x00\x00\x00\x0F\x00\x00\x74\x0D\x00\x00\x04\x11\x00\x00\x1C\x01\x00\x00\x1C\x01\x00\x00\x00\x0F\x00\x00\x0E\x0D\x00\x00\x04\x11\x00\x00\x00\x0F\x00\x00\x0E\x0D\x00\x00\x04\x11\x00\x00\x1C\x01\x00\x00\x00\x0F\x00\x00\x0E\x0D\x00\x00\x04\x11\x00\x00\x1C\x01\x00\x00\x1C\x01\x00\x00\x00\x0F\x00\x00\x75\x0D\x00\x00\x04\x11\x00\x00\x1C\x01\x00\x00\x00\x0F\x00\x00\x30\x0D\x00\x00\x04\x11\x00\x00\x1C\x01\x00\x00\x1C\x01\x00\x00\x00\x0F\x00\x00\x04\x0D\x00\x00\x04\x11\x00\x00\x1C\x01\x00\x00\x00\x0F\x00\x00\x78\x0D\x00\x00\x05\x11\x00\x00\x00\x0F\x00\x00\x78\x0D\x00\x00\x04\x11\x00\x00\x00\x0F\x00\x00\x02\x01\x00\x00\x00\x0B\x00\x00\x71\x03\x00\x00\x71\x03\x00\x00\x0D\x01\x00\x00\x07\x01\x00\x00\x00\x09\x00\x00\x0E\x03\x00\x00\x76\x03\x00\x00\x14\x01\x00\x00\x18\x03\x00\x00\x00\x01',
|
|
7
|
+
_globals = (b'\xFF\xFF\xFF\x0Bnumber_format_bf16',0,b'\xFF\xFF\xFF\x0Bnumber_format_fp32',1,b'\x00\x00\x51\x23vollo_rt_accelerator_block_size',0,b'\x00\x00\x51\x23vollo_rt_accelerator_num_cores',0,b'\x00\x00\x0C\x23vollo_rt_add_accelerator',0,b'\x00\x00\x23\x23vollo_rt_add_job',0,b'\x00\x00\x1C\x23vollo_rt_add_job_bf16',0,b'\x00\x00\x34\x23vollo_rt_add_job_bf16_partial_update',0,b'\x00\x00\x15\x23vollo_rt_add_job_fp32',0,b'\x00\x00\x2C\x23vollo_rt_add_job_partial_update',0,b'\x00\x00\x10\x23vollo_rt_add_vm',0,b'\x00\x00\x6A\x23vollo_rt_destroy',0,b'\x00\x00\x67\x23vollo_rt_destroy_err',0,b'\x00\x00\x5A\x23vollo_rt_get_raw_buffer',0,b'\x00\x00\x63\x23vollo_rt_get_raw_buffer_bytes',0,b'\x00\x00\x00\x23vollo_rt_init',0,b'\x00\x00\x03\x23vollo_rt_load_program',0,b'\x00\x00\x3D\x23vollo_rt_load_program_from_buffer',0,b'\x00\x00\x5E\x23vollo_rt_model_input_format',0,b'\x00\x00\x55\x23vollo_rt_model_input_num_elements',0,b'\x00\x00\x49\x23vollo_rt_model_input_shape',0,b'\x00\x00\x55\x23vollo_rt_model_input_shape_len',0,b'\x00\x00\x44\x23vollo_rt_model_input_streaming_dim',0,b'\x00\x00\x0C\x23vollo_rt_model_name',0,b'\x00\x00\x51\x23vollo_rt_model_num_inputs',0,b'\x00\x00\x51\x23vollo_rt_model_num_outputs',0,b'\x00\x00\x5E\x23vollo_rt_model_output_format',0,b'\x00\x00\x55\x23vollo_rt_model_output_num_elements',0,b'\x00\x00\x49\x23vollo_rt_model_output_shape',0,b'\x00\x00\x55\x23vollo_rt_model_output_shape_len',0,b'\x00\x00\x44\x23vollo_rt_model_output_streaming_dim',0,b'\x00\x00\x4E\x23vollo_rt_num_models',0,b'\x00\x00\x07\x23vollo_rt_poll',0,b'\x00\x00\x42\x23vollo_rt_version',0),
|
|
8
|
+
_struct_unions = ((b'\x00\x00\x00\x73\x00\x00\x00\x02partial_update_input',b'\x00\x00\x30\x11input_arg_num',b'\x00\x00\x30\x11num_updates',b'\x00\x00\x27\x11update_indices',b'\x00\x00\x3F\x11update_values'),),
|
|
9
|
+
_enums = (b'\x00\x00\x00\x6E\x00\x00\x00\x16number_format\x00number_format_bf16,number_format_fp32',),
|
|
10
|
+
_typenames = (b'\x00\x00\x00\x76bf16',b'\x00\x00\x00\x30number_format',b'\x00\x00\x00\x73partial_update_input',b'\x00\x00\x00\x04vollo_rt_context_t',b'\x00\x00\x00\x05vollo_rt_error_t'),
|
|
11
|
+
)
|
vollo_rt/__init__.py
ADDED
|
@@ -0,0 +1,590 @@
|
|
|
1
|
+
# Python bindings for the Vollo Runtime
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import Any, List, Tuple, Optional, Union
|
|
5
|
+
from _vollo_rt import ffi
|
|
6
|
+
|
|
7
|
+
import os
|
|
8
|
+
|
|
9
|
+
import torch
|
|
10
|
+
import numpy as np
|
|
11
|
+
|
|
12
|
+
import time
|
|
13
|
+
|
|
14
|
+
from collections.abc import Sequence
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def handle_error(output):
|
|
18
|
+
if output:
|
|
19
|
+
raise Exception(ffi.string(output).decode("utf-8"))
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class VolloRTContext:
|
|
23
|
+
"""
|
|
24
|
+
A context for performing computation on Vollo
|
|
25
|
+
|
|
26
|
+
This wraps the C bindings for the Vollo Runtime. In order for contexts to be
|
|
27
|
+
properly garbage collected, :class:`VolloRTContext` is a context manager, and should be
|
|
28
|
+
used in a ``with`` block. This ensures that the context id correctly destroyed
|
|
29
|
+
after use. :class:`VolloRTContext` should not be nested, only a single context should
|
|
30
|
+
be open at any given time.
|
|
31
|
+
|
|
32
|
+
The general order of operations is as follows:
|
|
33
|
+
- Initialise context in a ``with`` statement
|
|
34
|
+
- :meth:`add_accelerator`
|
|
35
|
+
- :meth:`load_program` / :meth:`load_program_bytes`
|
|
36
|
+
- Gather metadata about the models available in the loaded program
|
|
37
|
+
- Run inference with either:
|
|
38
|
+
- :meth:`run`
|
|
39
|
+
- Low level API:
|
|
40
|
+
- Add jobs with :meth:`add_job`, :meth:`add_job_f32` or :meth:`add_job_bf16`
|
|
41
|
+
- :meth:`poll` until a job is completed
|
|
42
|
+
- :meth:`get_result` to retrieve the result of the computation
|
|
43
|
+
|
|
44
|
+
High level API example:
|
|
45
|
+
|
|
46
|
+
.. code-block:: python
|
|
47
|
+
|
|
48
|
+
ctx.add_accelerator(0)
|
|
49
|
+
ctx.load_program("program.vollo")
|
|
50
|
+
|
|
51
|
+
input_arr = np.random.rand(100,50).astype(np.float32)
|
|
52
|
+
output = ctx.run(input_arr)
|
|
53
|
+
|
|
54
|
+
Low level API example:
|
|
55
|
+
|
|
56
|
+
.. code-block:: python
|
|
57
|
+
|
|
58
|
+
ctx.add_accelerator(0)
|
|
59
|
+
ctx.load_program("program.vollo")
|
|
60
|
+
|
|
61
|
+
# add jobs
|
|
62
|
+
input_arr = np.random.rand(100,50).astype(np.float32)
|
|
63
|
+
user_ctx_f32 = ctx.add_job_f32(input_arr)
|
|
64
|
+
|
|
65
|
+
# loop until the job is complete
|
|
66
|
+
completed_jobs = []
|
|
67
|
+
while(user_ctx_f32 not in completed_jobs):
|
|
68
|
+
completed_jobs = completed_jobs + ctx.poll()
|
|
69
|
+
|
|
70
|
+
# retrieve the results from each computation
|
|
71
|
+
output_f32 = ctx.get_result(user_ctx_f32)
|
|
72
|
+
"""
|
|
73
|
+
|
|
74
|
+
def __init__(self):
|
|
75
|
+
try:
|
|
76
|
+
self.lib = ffi.dlopen("libvollo_rt.so")
|
|
77
|
+
except Exception:
|
|
78
|
+
raise Exception(
|
|
79
|
+
"""
|
|
80
|
+
Could not load the Vollo RT library!
|
|
81
|
+
|
|
82
|
+
Make sure to "source $VOLLO_SDK/setup.sh", or to set "$LD_LIBRARY_PATH" appropriately.
|
|
83
|
+
See https://vollo.myrtle.ai/latest/vollo-runtime.html for more information.
|
|
84
|
+
"""
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
_ptr = ffi.new("void **")
|
|
88
|
+
handle_error(self.lib.vollo_rt_init(_ptr))
|
|
89
|
+
|
|
90
|
+
# Keep inputs alive until their jobs have been completed
|
|
91
|
+
self._context_input_map = {}
|
|
92
|
+
|
|
93
|
+
self._context_output_map = {}
|
|
94
|
+
self._context_counter = -1
|
|
95
|
+
self._ctx = _ptr[0]
|
|
96
|
+
|
|
97
|
+
self.number_format_bf16 = self.lib.number_format_bf16
|
|
98
|
+
self.number_format_fp32 = self.lib.number_format_fp32
|
|
99
|
+
|
|
100
|
+
def __enter__(self):
|
|
101
|
+
return self
|
|
102
|
+
|
|
103
|
+
def _make_unique_context(self) -> int:
|
|
104
|
+
self._context_counter += 1
|
|
105
|
+
return self._context_counter
|
|
106
|
+
|
|
107
|
+
def add_accelerator(self, accelerator_index: int):
|
|
108
|
+
"""
|
|
109
|
+
Add an accelerator.
|
|
110
|
+
The accelerator is specified by its index. The index refers to an accelerator in the sorted list
|
|
111
|
+
of PCI addresses.
|
|
112
|
+
"""
|
|
113
|
+
handle_error(
|
|
114
|
+
self.lib.vollo_rt_add_accelerator(
|
|
115
|
+
self._ctx, ffi.cast("size_t", accelerator_index)
|
|
116
|
+
)
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
def add_vm(
|
|
120
|
+
self,
|
|
121
|
+
accelerator_index: int,
|
|
122
|
+
bit_accurate: bool,
|
|
123
|
+
):
|
|
124
|
+
"""
|
|
125
|
+
Add a VM, to run a program in software simulation rather than on hardware.
|
|
126
|
+
Allows testing the API without needing an accelerator or license, giving correct results but much slower.
|
|
127
|
+
|
|
128
|
+
You can choose any `accelerator_index` to assign to the VM then use the rest of the API as though the VM
|
|
129
|
+
is an accelerator. However, the VM hardware config is determined by the requirements of the loaded program,
|
|
130
|
+
so until you call `vollo_rt_load_program` the values returned by `accelerator_num_cores` and
|
|
131
|
+
`accelerator_block_size` will be 0.
|
|
132
|
+
|
|
133
|
+
Cannot currently be used with Vollo Trees programs.
|
|
134
|
+
|
|
135
|
+
This should be called before `load_program`.
|
|
136
|
+
|
|
137
|
+
Arg:
|
|
138
|
+
|
|
139
|
+
bit_accurate: Use a compute model that replicates the VOLLO accelerator with bit-accuracy. Disable
|
|
140
|
+
to use single precision compute.
|
|
141
|
+
"""
|
|
142
|
+
handle_error(
|
|
143
|
+
self.lib.vollo_rt_add_vm(
|
|
144
|
+
self._ctx,
|
|
145
|
+
ffi.cast("size_t", accelerator_index),
|
|
146
|
+
ffi.cast("bool", bit_accurate),
|
|
147
|
+
)
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
def accelerator_num_cores(self, accelerator_index: int) -> int:
|
|
151
|
+
"""
|
|
152
|
+
Get the number of cores of a Vollo accelerator.
|
|
153
|
+
For Vollo Trees bitstreams, this is the number of tree units.
|
|
154
|
+
|
|
155
|
+
If used on a VM before loading a program, it will return 0, because the VM hardware config is determined by
|
|
156
|
+
the requirements of the loaded program.
|
|
157
|
+
"""
|
|
158
|
+
return self.lib.vollo_rt_accelerator_num_cores(self._ctx, accelerator_index)
|
|
159
|
+
|
|
160
|
+
def accelerator_block_size(self, accelerator_index: int) -> int:
|
|
161
|
+
"""
|
|
162
|
+
Get the block size of a Vollo accelerator.
|
|
163
|
+
|
|
164
|
+
If used on a VM before loading a program, it will return 0, because the VM hardware config is determined by
|
|
165
|
+
the requirements of the loaded program.
|
|
166
|
+
"""
|
|
167
|
+
return self.lib.vollo_rt_accelerator_block_size(self._ctx, accelerator_index)
|
|
168
|
+
|
|
169
|
+
def load_program(
|
|
170
|
+
self,
|
|
171
|
+
program: Union[
|
|
172
|
+
str,
|
|
173
|
+
os.PathLike,
|
|
174
|
+
Any,
|
|
175
|
+
],
|
|
176
|
+
):
|
|
177
|
+
"""
|
|
178
|
+
Load a pre-compiled program onto the accelerator.
|
|
179
|
+
|
|
180
|
+
Arg:
|
|
181
|
+
|
|
182
|
+
program: One of:
|
|
183
|
+
|
|
184
|
+
A path to a Vollo program (typically .vollo)
|
|
185
|
+
|
|
186
|
+
A program straight from the Vollo Compiler or the Vollo Trees Compiler
|
|
187
|
+
"""
|
|
188
|
+
if isinstance(program, str) or isinstance(program, os.PathLike):
|
|
189
|
+
handle_error(
|
|
190
|
+
self.lib.vollo_rt_load_program(self._ctx, str(program).encode("utf-8"))
|
|
191
|
+
)
|
|
192
|
+
else:
|
|
193
|
+
try:
|
|
194
|
+
bytes = program.save_bytes()
|
|
195
|
+
except AttributeError:
|
|
196
|
+
raise Exception(
|
|
197
|
+
"load_program: Unsupported type, expected a path or a Vollo program"
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
self.load_program_bytes(bytes)
|
|
201
|
+
|
|
202
|
+
def load_program_bytes(self, program_bytes: bytes):
|
|
203
|
+
"""
|
|
204
|
+
Load a pre-compiled Vollo program from a bytes object
|
|
205
|
+
"""
|
|
206
|
+
if not isinstance(program_bytes, bytes):
|
|
207
|
+
raise TypeError("program_bytes must be of type bytes")
|
|
208
|
+
|
|
209
|
+
handle_error(
|
|
210
|
+
self.lib.vollo_rt_load_program_from_buffer(
|
|
211
|
+
self._ctx, program_bytes, len(program_bytes)
|
|
212
|
+
)
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
def num_models(self) -> int:
|
|
216
|
+
"""
|
|
217
|
+
The number of models in the loaded program.
|
|
218
|
+
"""
|
|
219
|
+
return self.lib.vollo_rt_num_models(self._ctx)
|
|
220
|
+
|
|
221
|
+
def model_name(self, model_index: int = 0) -> Optional[str]:
|
|
222
|
+
"""
|
|
223
|
+
Get the name of a model if set
|
|
224
|
+
"""
|
|
225
|
+
name = self.lib.vollo_rt_model_name(self._ctx, model_index)
|
|
226
|
+
|
|
227
|
+
if name:
|
|
228
|
+
return ffi.string(name).decode("utf-8")
|
|
229
|
+
else:
|
|
230
|
+
return None
|
|
231
|
+
|
|
232
|
+
def model_num_inputs(self, model_index: int = 0) -> int:
|
|
233
|
+
"""
|
|
234
|
+
Get the number of inputs the model uses.
|
|
235
|
+
"""
|
|
236
|
+
return self.lib.vollo_rt_model_num_inputs(self._ctx, model_index)
|
|
237
|
+
|
|
238
|
+
def model_num_outputs(self, model_index: int = 0) -> int:
|
|
239
|
+
"""
|
|
240
|
+
Get the number of outputs the model uses.
|
|
241
|
+
"""
|
|
242
|
+
return self.lib.vollo_rt_model_num_outputs(self._ctx, model_index)
|
|
243
|
+
|
|
244
|
+
def model_input_shape(
|
|
245
|
+
self, model_index: int = 0, input_index: int = 0
|
|
246
|
+
) -> Tuple[int]:
|
|
247
|
+
"""
|
|
248
|
+
Get the shape of a model input
|
|
249
|
+
"""
|
|
250
|
+
raw_array = self.lib.vollo_rt_model_input_shape(
|
|
251
|
+
self._ctx, model_index, input_index
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
shape_len = self.lib.vollo_rt_model_input_shape_len(
|
|
255
|
+
self._ctx, model_index, input_index
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
shape = []
|
|
259
|
+
for i in range(shape_len):
|
|
260
|
+
shape.append(raw_array[i])
|
|
261
|
+
|
|
262
|
+
return tuple(shape)
|
|
263
|
+
|
|
264
|
+
def model_output_shape(
|
|
265
|
+
self, model_index: int = 0, output_index: int = 0
|
|
266
|
+
) -> Tuple[int]:
|
|
267
|
+
"""
|
|
268
|
+
Get the shape of a model output
|
|
269
|
+
"""
|
|
270
|
+
raw_array = self.lib.vollo_rt_model_output_shape(
|
|
271
|
+
self._ctx, model_index, output_index
|
|
272
|
+
)
|
|
273
|
+
|
|
274
|
+
shape_len = self.lib.vollo_rt_model_output_shape_len(
|
|
275
|
+
self._ctx, model_index, output_index
|
|
276
|
+
)
|
|
277
|
+
|
|
278
|
+
shape = []
|
|
279
|
+
for i in range(shape_len):
|
|
280
|
+
shape.append(raw_array[i])
|
|
281
|
+
|
|
282
|
+
return tuple(shape)
|
|
283
|
+
|
|
284
|
+
def model_input_streaming_dim(
|
|
285
|
+
self, model_index: int = 0, input_index: int = 0
|
|
286
|
+
) -> Optional[int]:
|
|
287
|
+
"""
|
|
288
|
+
Get the input streaming dimension or None
|
|
289
|
+
"""
|
|
290
|
+
dim = self.lib.vollo_rt_model_input_streaming_dim(
|
|
291
|
+
self._ctx, model_index, input_index
|
|
292
|
+
)
|
|
293
|
+
|
|
294
|
+
if dim == -1:
|
|
295
|
+
return None
|
|
296
|
+
|
|
297
|
+
return dim
|
|
298
|
+
|
|
299
|
+
def model_output_streaming_dim(
|
|
300
|
+
self, model_index: int = 0, output_index: int = 0
|
|
301
|
+
) -> Optional[int]:
|
|
302
|
+
"""
|
|
303
|
+
Get the output streaming dimension or None
|
|
304
|
+
"""
|
|
305
|
+
dim = self.lib.vollo_rt_model_output_streaming_dim(
|
|
306
|
+
self._ctx, model_index, output_index
|
|
307
|
+
)
|
|
308
|
+
|
|
309
|
+
if dim == -1:
|
|
310
|
+
return None
|
|
311
|
+
|
|
312
|
+
return dim
|
|
313
|
+
|
|
314
|
+
def model_output_format(self, model_index: int = 0, output_index: int = 0):
|
|
315
|
+
"""
|
|
316
|
+
Get the native number format (bf16 or fp32) of a specific output of the model.
|
|
317
|
+
Returns the enum value (self.number_format_bf16 or self.number_format_fp32).
|
|
318
|
+
"""
|
|
319
|
+
return self.lib.vollo_rt_model_output_format(
|
|
320
|
+
self._ctx, model_index, output_index
|
|
321
|
+
)
|
|
322
|
+
|
|
323
|
+
def _get_dtype_from_format(self, fmt, use_torch: bool):
|
|
324
|
+
"""Helper to convert vollo number format to torch/numpy dtype"""
|
|
325
|
+
if fmt == self.lib.number_format_bf16:
|
|
326
|
+
if use_torch:
|
|
327
|
+
return torch.bfloat16
|
|
328
|
+
else:
|
|
329
|
+
# Numpy has no native bfloat16, usually we fall back to float32 or raise error.
|
|
330
|
+
# Since Vollo driver handles conversion, we can't really hold bf16 in numpy.
|
|
331
|
+
raise ValueError("Numpy does not support bfloat16 output")
|
|
332
|
+
elif fmt == self.lib.number_format_fp32:
|
|
333
|
+
return torch.float32 if use_torch else np.float32
|
|
334
|
+
else:
|
|
335
|
+
raise ValueError(f"Unknown format: {fmt}")
|
|
336
|
+
|
|
337
|
+
def add_job(self, inputs, model_index: int = 0, output_formats=None):
|
|
338
|
+
"""
|
|
339
|
+
Sets up a computation on the vollo.
|
|
340
|
+
|
|
341
|
+
Args:
|
|
342
|
+
inputs: A Tensor/Array or Sequence of Tensors/Arrays.
|
|
343
|
+
model_index: The index of the model to use.
|
|
344
|
+
output_formats: (Optional) A list of vollo number_formats (self.number_format_bf16/number_format_fp32)
|
|
345
|
+
specifying the desired output types. If None, the model's
|
|
346
|
+
native output formats are used.
|
|
347
|
+
|
|
348
|
+
Returns:
|
|
349
|
+
User context handle. The results (retrieved via poll) will match the
|
|
350
|
+
types specified in output_formats (or the model's native types).
|
|
351
|
+
"""
|
|
352
|
+
if not isinstance(inputs, Sequence):
|
|
353
|
+
inputs = [inputs]
|
|
354
|
+
else:
|
|
355
|
+
inputs = list(inputs)
|
|
356
|
+
|
|
357
|
+
num_inputs = self.model_num_inputs(model_index)
|
|
358
|
+
assert (
|
|
359
|
+
len(inputs) == num_inputs
|
|
360
|
+
), f"add_job: Was given {len(inputs)} inputs but the program expects {num_inputs} inputs"
|
|
361
|
+
|
|
362
|
+
user_ctx = self._make_unique_context()
|
|
363
|
+
self._context_input_map[user_ctx] = []
|
|
364
|
+
|
|
365
|
+
# 1. Prepare Input Buffers & Formats
|
|
366
|
+
c_input_ptrs = ffi.new(f"void *[{num_inputs}]")
|
|
367
|
+
c_in_fmt_arr = ffi.new(f"number_format[{num_inputs}]")
|
|
368
|
+
|
|
369
|
+
# We track if we see any torch tensors to decide if outputs should be torch or numpy
|
|
370
|
+
any_torch = False
|
|
371
|
+
|
|
372
|
+
for i, inp in enumerate(inputs):
|
|
373
|
+
expected_shape = self.model_input_shape(model_index, i)
|
|
374
|
+
assert tuple(inp.shape) == expected_shape
|
|
375
|
+
|
|
376
|
+
fmt = None
|
|
377
|
+
ptr = None
|
|
378
|
+
|
|
379
|
+
if isinstance(inp, torch.Tensor):
|
|
380
|
+
any_torch = True
|
|
381
|
+
inp = inp.contiguous()
|
|
382
|
+
if inp.dtype == torch.bfloat16:
|
|
383
|
+
fmt = self.number_format_bf16
|
|
384
|
+
elif inp.dtype == torch.float32:
|
|
385
|
+
fmt = self.number_format_fp32
|
|
386
|
+
else:
|
|
387
|
+
raise TypeError(
|
|
388
|
+
f"add_job: Unsupported torch dtype at input {i}: {inp.dtype}"
|
|
389
|
+
)
|
|
390
|
+
ptr = inp.data_ptr()
|
|
391
|
+
|
|
392
|
+
elif isinstance(inp, np.ndarray):
|
|
393
|
+
if inp.dtype == np.float32:
|
|
394
|
+
inp = np.ascontiguousarray(inp)
|
|
395
|
+
fmt = self.number_format_fp32
|
|
396
|
+
else:
|
|
397
|
+
raise TypeError(
|
|
398
|
+
f"add_job: Unsupported numpy dtype at input {i}: {inp.dtype}"
|
|
399
|
+
)
|
|
400
|
+
ptr = inp.ctypes.data
|
|
401
|
+
else:
|
|
402
|
+
raise TypeError(
|
|
403
|
+
f"add_job: Unsupported input type at index {i}: {type(inp)}"
|
|
404
|
+
)
|
|
405
|
+
|
|
406
|
+
c_in_fmt_arr[i] = fmt
|
|
407
|
+
c_input_ptrs[i] = ffi.cast("void *", ptr)
|
|
408
|
+
self._context_input_map[user_ctx].append(inp)
|
|
409
|
+
|
|
410
|
+
# 2. Determine Output Formats
|
|
411
|
+
num_outputs = self.model_num_outputs(model_index)
|
|
412
|
+
|
|
413
|
+
# If no specific output formats requested, either use model native formats (if any torch
|
|
414
|
+
# input), or force fp32 (if all numpy inputs)
|
|
415
|
+
if output_formats is None:
|
|
416
|
+
if not any_torch:
|
|
417
|
+
# numpy doesn't support bf16, so we have to force fp32 outputs
|
|
418
|
+
output_formats = [self.number_format_fp32] * num_outputs
|
|
419
|
+
else:
|
|
420
|
+
output_formats = [
|
|
421
|
+
self.model_output_format(model_index, i) for i in range(num_outputs)
|
|
422
|
+
]
|
|
423
|
+
|
|
424
|
+
assert len(output_formats) == num_outputs
|
|
425
|
+
|
|
426
|
+
# 3. Prepare Output Buffers
|
|
427
|
+
outputs = []
|
|
428
|
+
c_output_ptrs = ffi.new(f"void *[{num_outputs}]")
|
|
429
|
+
c_out_fmt_arr = ffi.new(f"number_format[{num_outputs}]")
|
|
430
|
+
|
|
431
|
+
for i, fmt in enumerate(output_formats):
|
|
432
|
+
out_shape = self.model_output_shape(model_index, i)
|
|
433
|
+
|
|
434
|
+
# Determine python dtype based on the requested format and whether inputs were torch/numpy
|
|
435
|
+
# If inputs were numpy but format is bf16, we have a problem (numpy can't hold bf16).
|
|
436
|
+
# We assume if the user passed numpy, they expect fp32 or the model allows fp32.
|
|
437
|
+
|
|
438
|
+
if not any_torch and fmt == self.number_format_bf16:
|
|
439
|
+
# Fallback: If inputs are numpy but output requires bf16, we can't return numpy bf16.
|
|
440
|
+
# We raise an error or force the user to use torch.
|
|
441
|
+
# Alternatively, we could cast to fp32 here, but that ignores the 'fmt' argument.
|
|
442
|
+
raise ValueError(
|
|
443
|
+
f"Output {i} is bf16, but inputs are numpy arrays. "
|
|
444
|
+
"Numpy does not support bfloat16. Please use torch tensors or request fp32 output."
|
|
445
|
+
)
|
|
446
|
+
|
|
447
|
+
# Map format to dtype
|
|
448
|
+
dtype = self._get_dtype_from_format(fmt, use_torch=any_torch)
|
|
449
|
+
|
|
450
|
+
if any_torch:
|
|
451
|
+
out_tensor = torch.zeros(out_shape, dtype=dtype)
|
|
452
|
+
ptr = out_tensor.data_ptr()
|
|
453
|
+
outputs.append(out_tensor)
|
|
454
|
+
else:
|
|
455
|
+
out_array = np.zeros(out_shape, dtype=dtype)
|
|
456
|
+
ptr = out_array.ctypes.data
|
|
457
|
+
outputs.append(out_array)
|
|
458
|
+
|
|
459
|
+
c_output_ptrs[i] = ffi.cast("void *", ptr)
|
|
460
|
+
c_out_fmt_arr[i] = fmt
|
|
461
|
+
|
|
462
|
+
self._context_output_map[user_ctx] = outputs
|
|
463
|
+
|
|
464
|
+
# 4. Call C Function
|
|
465
|
+
handle_error(
|
|
466
|
+
self.lib.vollo_rt_add_job(
|
|
467
|
+
self._ctx,
|
|
468
|
+
ffi.cast("size_t", model_index),
|
|
469
|
+
ffi.cast("uint64_t", user_ctx),
|
|
470
|
+
c_in_fmt_arr,
|
|
471
|
+
c_input_ptrs,
|
|
472
|
+
c_out_fmt_arr,
|
|
473
|
+
c_output_ptrs,
|
|
474
|
+
)
|
|
475
|
+
)
|
|
476
|
+
|
|
477
|
+
return user_ctx
|
|
478
|
+
|
|
479
|
+
def add_job_f32(self, inputs, model_index: int = 0) -> int:
|
|
480
|
+
"""
|
|
481
|
+
Sets up a computation where inputs and outputs are float32.
|
|
482
|
+
"""
|
|
483
|
+
# 1. Check inputs
|
|
484
|
+
check_inputs = inputs if isinstance(inputs, Sequence) else [inputs]
|
|
485
|
+
for i, inp in enumerate(check_inputs):
|
|
486
|
+
if isinstance(inp, torch.Tensor):
|
|
487
|
+
if inp.dtype != torch.float32:
|
|
488
|
+
raise TypeError(
|
|
489
|
+
f"add_job_f32: Input {i} is torch.{inp.dtype}, expected float32"
|
|
490
|
+
)
|
|
491
|
+
elif isinstance(inp, np.ndarray):
|
|
492
|
+
if inp.dtype != np.float32:
|
|
493
|
+
raise TypeError(
|
|
494
|
+
f"add_job_f32: Input {i} is numpy.{inp.dtype}, expected float32"
|
|
495
|
+
)
|
|
496
|
+
else:
|
|
497
|
+
raise TypeError(f"add_job_f32: Unsupported type {type(inp)}")
|
|
498
|
+
|
|
499
|
+
# 2. Force outputs to FP32
|
|
500
|
+
num_outputs = self.model_num_outputs(model_index)
|
|
501
|
+
forced_formats = [self.number_format_fp32] * num_outputs
|
|
502
|
+
|
|
503
|
+
return self.add_job(inputs, model_index, output_formats=forced_formats)
|
|
504
|
+
|
|
505
|
+
def add_job_bf16(self, inputs, model_index: int = 0):
|
|
506
|
+
"""
|
|
507
|
+
Sets up a computation where inputs and outputs are bfloat16.
|
|
508
|
+
"""
|
|
509
|
+
# 1. Check inputs
|
|
510
|
+
check_inputs = inputs if isinstance(inputs, Sequence) else [inputs]
|
|
511
|
+
for i, inp in enumerate(check_inputs):
|
|
512
|
+
if isinstance(inp, torch.Tensor):
|
|
513
|
+
if inp.dtype != torch.bfloat16:
|
|
514
|
+
raise TypeError(
|
|
515
|
+
f"add_job_bf16: Input {i} is torch.{inp.dtype}, expected bfloat16"
|
|
516
|
+
)
|
|
517
|
+
else:
|
|
518
|
+
raise TypeError(
|
|
519
|
+
f"add_job_bf16: Input {i} must be a torch tensor (Numpy does not support bfloat16)"
|
|
520
|
+
)
|
|
521
|
+
|
|
522
|
+
# 2. Force outputs to BF16
|
|
523
|
+
num_outputs = self.model_num_outputs(model_index)
|
|
524
|
+
forced_formats = [self.number_format_bf16] * num_outputs
|
|
525
|
+
|
|
526
|
+
return self.add_job(inputs, model_index, output_formats=forced_formats)
|
|
527
|
+
|
|
528
|
+
def poll(self) -> List[int]:
|
|
529
|
+
"""
|
|
530
|
+
Poll the vollo for completion.
|
|
531
|
+
Returns a list of user contexts corresponding to completed jobs.
|
|
532
|
+
|
|
533
|
+
Note: Polling also initiates transfers for new jobs, so you must poll before any progress
|
|
534
|
+
on these new jobs can be made.
|
|
535
|
+
"""
|
|
536
|
+
num_completed_ptr = ffi.new("size_t *")
|
|
537
|
+
user_ctxs_ptr = ffi.new("uint64_t **")
|
|
538
|
+
handle_error(
|
|
539
|
+
self.lib.vollo_rt_poll(self._ctx, num_completed_ptr, user_ctxs_ptr)
|
|
540
|
+
)
|
|
541
|
+
results = [int(user_ctxs_ptr[0][i]) for i in range(int(num_completed_ptr[0]))]
|
|
542
|
+
# Safe to clean up inputs once their job has completed
|
|
543
|
+
for user_ctx in results:
|
|
544
|
+
self._context_input_map.pop(user_ctx)
|
|
545
|
+
return results
|
|
546
|
+
|
|
547
|
+
def get_result(self, user_ctx: int):
|
|
548
|
+
"""
|
|
549
|
+
Retrieve the result of the computation corresponding to ``user_ctx``
|
|
550
|
+
"""
|
|
551
|
+
outputs = self._context_output_map[user_ctx]
|
|
552
|
+
return outputs[0] if len(outputs) == 1 else tuple(outputs)
|
|
553
|
+
|
|
554
|
+
def run(
|
|
555
|
+
self,
|
|
556
|
+
inputs,
|
|
557
|
+
model_index: int = 0,
|
|
558
|
+
max_poll_iterations: int = 20_000_000_000,
|
|
559
|
+
sleep_duration_ms: Optional[float] = None,
|
|
560
|
+
):
|
|
561
|
+
"""
|
|
562
|
+
Run a single inference of a model on Vollo
|
|
563
|
+
|
|
564
|
+
This is a simpler API to run single inferences without needing to
|
|
565
|
+
use :meth:`add_job`, :meth:`poll` and :meth:`get_result` manually
|
|
566
|
+
|
|
567
|
+
Arg:
|
|
568
|
+
|
|
569
|
+
sleep_duration_ms: The number of milliseconds to wait between each poll. There will be no wait if set to None.
|
|
570
|
+
"""
|
|
571
|
+
user_ctx = self.add_job(inputs, model_index)
|
|
572
|
+
|
|
573
|
+
poll_count = 0
|
|
574
|
+
|
|
575
|
+
# time.sleep() takes in argument as seconds, but we've taken sleep_duration_ms in as milliseconds
|
|
576
|
+
if sleep_duration_ms is not None:
|
|
577
|
+
sleep_duration_ms /= 1_000
|
|
578
|
+
|
|
579
|
+
while user_ctx not in self.poll():
|
|
580
|
+
poll_count += 1
|
|
581
|
+
if poll_count == max_poll_iterations:
|
|
582
|
+
raise TimeoutError
|
|
583
|
+
|
|
584
|
+
if sleep_duration_ms is not None:
|
|
585
|
+
time.sleep(sleep_duration_ms)
|
|
586
|
+
|
|
587
|
+
return self.get_result(user_ctx)
|
|
588
|
+
|
|
589
|
+
def __exit__(self, *args):
|
|
590
|
+
handle_error(self.lib.vollo_rt_destroy(self._ctx))
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
MYRTLE SOFTWARE END USER LICENSE AGREEMENT (“EULA”)
|
|
2
|
+
PLEASE READ THIS AGREEMENT CAREFULLY.
|
|
3
|
+
THIS EULA, (TOGETHER WITH THE EVALUATION FORM, THE "AGREEMENT"), IS ENTERED INTO BETWEEN YOU (“USER”) AND MYRTLE SOFTWARE LTD, A COMPANY INCORPORATED UNDER THE LAWS OF ENGLAND AND WALES AT THIRD FLOOR, ST ANDREWS HOUSE, 59 ST ANDREWS STREET, CAMBRIDGE CB2 3BZ, COMPANY NUMBER 4978210 (THE "COMPANY"), WHICH APPLIES TO USER'S USE OF THE COMPANY'S SOFTWARE, DOCUMENTATION AND CONTENT.
|
|
4
|
+
USER AND THE COMPANY MAY EACH BE REFERRED TO AS A “PARTY” AND TOGETHER AS THE “PARTIES”. IF THE USER DOWNLOADS, INSTALLS, ACCESSES, OR OTHERWISE USES ANY OF THE SERVICES, USER HEREBY AGREES TO AND SHALL BE BOUND BY THE TERMS OF THIS EULA.
|
|
5
|
+
IF USER DOES NOT AGREE TO THE TERMS OF THIS EULA, THE USER IS NOT PERMITTED TO PROCEED FURTHER OR USE ANY OF THE COMPANY SERVICE. COMPANY RESERVES THE RIGHT TO CHANGE THE TERMS OF THIS EULA AT ANY TIME UPON THIRTY (30) DAYS WRITTEN NOTICE THROUGH OUR WEBSITE.
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
1. DEFINITIONS AND INTERPRETATIONS
|
|
9
|
+
1. "Authorised Reseller" means a reseller that is enrolled with the Company under a partner programme or similar arrangement.
|
|
10
|
+
"Authorised User" means an employee, contractor or consultant of the User who has log in credentials for, or access to, the Services.
|
|
11
|
+
"Confidential Information" means all confidential or proprietary information (however recorded or preserved) disclosed by one party or its employees, officers, subcontractors, representatives or advisers to the other party and the other party’s representatives, including the terms of this Agreement, the business, affairs, customers, clients, suppliers, plans, intentions, market opportunities, operations, processes, products, services, data, know-how, or trade secrets of the disclosing party.
|
|
12
|
+
"Derived Data" means any data which is derived from User's use of the Services, which shall include: (i) any meta-data created in the User's use of the Services such as the number of connections and volume of data; (ii) any data which is processed and stored as mathematical constructs; and (iii) statistical or aggregated data, but shall exclude any personal data.
|
|
13
|
+
"E-Portal" means shall mean the e-ticketing portal provided by the Authorised Reseller to raise any issues that need to be resolved by the Company and that require Support.
|
|
14
|
+
"Intellectual Property Rights" means patents, rights to inventions, copyright and neighbouring and related rights, trade marks, goodwill and all other intellectual property rights, in each case whether registered or unregistered and including all applications and rights to apply for and be granted, renewals or extensions of, and rights to claim priority from, such rights and all similar or equivalent rights or forms of protection which subsist or will subsist now or in the future in any part of the world.
|
|
15
|
+
"Rights" means individually or collectively, Services, all software, hardware, algorithms, methodologies, Derived Data, other technology used by the Company to provide the Services, and all Intellectual Property Rights and proprietary rights in all of the foregoing.
|
|
16
|
+
"Services" means the provision of the Company's software, documentation and content when as purchased by the User from the Company or Authorised reseller.
|
|
17
|
+
"Support" means the support services that the Company will provide to the User during the period of use of the Services.
|
|
18
|
+
"Website" means www.myrtle.ai.
|
|
19
|
+
2. EVALUATIONS AND BETA TESTING
|
|
20
|
+
1. This clause 2 applies if the Company has agreed to provide the User with a non-transferable, non-exclusive, revocable, non-sublicensable license to access the Services to either: (a) conduct a proof of value of the Services (a "Proof of Value"); or (b) conduct a technical preview (a "Product Review") of a product of the Company which may or may not include unreleased features (a "Beta Product"), free of charge for the Evaluation Period specified in the Evaluation Form. Either Party may terminate a Proof of Value or Product Review for any reason on no less than 7 days' notice to the other. During an Evaluation Period, in addition to the restrictions set out at clauses 3.2 and 3.3 below, the User may be provided with access to test data in a non-live environment only, on the terms of this Agreement.
|
|
21
|
+
2. Services and/or Beta Products provided to Customer during an Evaluation Period are provided "as is" and the Company provides no representations, warranties or guarantees whether express or implied regarding the Services. To the fullest extent permitted by applicable law, the Company shall have no liability to the Customer whether in contract, tort or otherwise and clause 8.4 shall not apply.
|
|
22
|
+
3. On expiry or termination of the Evaluation Period any rights granted to the User herein shall cease and the provisions of clause 7 shall apply.
|
|
23
|
+
3. ACCESS TO THE SERVICE
|
|
24
|
+
1. Subject to the terms and conditions of this EULA and any agreement agreed between the User and Company, the Company hereby grants the User a non-exclusive, non-transferable license, during the term of the Agreement and subject to the terms of the Agreement, to use and access the Services, solely in accordance with the published documentation for the Services, for the Users own internal-use purposes.
|
|
25
|
+
2. The User agrees not to:
|
|
26
|
+
1. permit any third party to access and/or use the Services;
|
|
27
|
+
2. rent, lease, loan, or sell access to the Services to any third party;
|
|
28
|
+
3. interfere with, disrupt, alter, translate, or modify the Services or any part thereof, or create an undue burden on the Services or the networks or services connected to the Services;
|
|
29
|
+
4. reverse-engineer the Services (except to the extent that such restriction on reverse engineering is prohibited by law in which case User shall provide the Company with prompt written notice prior to any such action), or access the Services to build a competitive product or service; or
|
|
30
|
+
5. introduce software or automated agents or scripts to the Services so as to produce multiple accounts, generate automated searches, requests and queries, or to strip or mine data from the Services.
|
|
31
|
+
3. The Services, including any accounts, passwords or other such log in or access information, may not be used by more than one individual user, and User agrees not to assist with or permit this.
|
|
32
|
+
4. The Company reserves the right, at its discretion, to suspend or terminate any use and access to the Services that the Company reasonably determines have been used by an unauthorised third party.
|
|
33
|
+
4. OWNERSHIP AND INTELLECTUAL PROPERTY RIGHTS
|
|
34
|
+
1. The User acknowledges and agrees that the Rights, shall be the exclusive property of the Company.
|
|
35
|
+
2. The User hereby assigns to the Company any suggestions, ideas, enhancement requests, improvements, feedback, recommendations or other information provided by the User related to the Services.
|
|
36
|
+
3. All rights not expressly granted to the User are reserved to the Company.
|
|
37
|
+
4. The Company makes no representation or warranty as to the validity or enforceability of the intellectual property rights in the Services.
|
|
38
|
+
5. Subject to clause 4.6 and 4.7, the Company shall defend the User against any third party claim that the use of the Services in accordance with this Agreement infringes any third party intellectual property right and shall indemnify the User for and against any amounts awarded against the User in judgment or settlement of such claims, provided that:
|
|
39
|
+
1. the Company is given prompt notice of such claim;
|
|
40
|
+
2. User provides reasonable co-operation to the Company in the defence and settlement of such claim, at the Company’s expense;
|
|
41
|
+
3. the Company is given sole authority to defend or settle the claim; and
|
|
42
|
+
4. the User makes no admission of liability or fault itself or on behalf of the Company.
|
|
43
|
+
6. In the defence or settlement of any claim pursuant to clause 4.5 above, the Company may at its sole option and expense either:
|
|
44
|
+
1. procure for the User the right to continue using the Services in the manner contemplated by this Agreement;
|
|
45
|
+
2. replace or modify the Services so that it becomes non-infringing; or
|
|
46
|
+
3. terminate this Agreement immediately by providing written notice to the User, without liability to the User.
|
|
47
|
+
7. The Company shall not be required to indemnify the User and disclaims all liability to the User, to the fullest extent permissible by applicable law, if the alleged infringement is based on:
|
|
48
|
+
1. modification of the Services by anyone other than the Company; or
|
|
49
|
+
2. the User or any Authorised User’s use of the Services otherwise than in accordance with this Agreement or in a manner contrary to the instructions given to the User by the Company; or
|
|
50
|
+
3. the User or any Authorised User’s use of the Services after notice of the alleged or actual infringement from the Company or any appropriate authority; or
|
|
51
|
+
4. use or combination of the Services with any other software or hardware, in circumstances where, but for such combination, no infringement would have occurred.
|
|
52
|
+
8. User shall defend the Company against all, or any costs, claims, damages or expenses incurred by the Company in respect of any third party claim relating to the Customer’s or any Authorised User’s use of the Services otherwise than in accordance with this Agreement, provided that:
|
|
53
|
+
1. the User is given prompt notice of such claim;
|
|
54
|
+
2. the Company provides reasonable co-operation to the User in the defence and settlement of such claim, at the User’s expense;
|
|
55
|
+
3. the User is given sole authority to defend or settle the claim;
|
|
56
|
+
4. the Company makes no admission of liability or fault itself or on behalf of the User;
|
|
57
|
+
5. any settlement will not entail an admission of fault or guilt by Company; and
|
|
58
|
+
9. the settlement includes, as an unconditional term, the claimant’s or the plaintiff’s release of Company from all liability in respect of the claim).
|
|
59
|
+
5. CONFIDENTIAL INFORMATION
|
|
60
|
+
1. User will not use any Confidential Information for any purpose not expressly permitted by this EULA, and will disclose the Confidential Information only to the employees, consultants (to the extent acting on the User's behalf and for its benefit), and agents of the User who have a need to know such Confidential Information for purposes of the Agreement and who are under a duty of confidentiality no less restrictive than the User’s duty hereunder.
|
|
61
|
+
2. The User will protect the Confidential Information from unauthorised use, access, or disclosure in the same manner as the User protects its own confidential or proprietary information of a similar nature and with no less than reasonable care.
|
|
62
|
+
3. The User will be allowed to disclose the Confidential Information to the extent that such disclosure is:
|
|
63
|
+
1. specifically approved in writing by the Company,
|
|
64
|
+
2. necessary in the course of legal proceedings for the User to defend itself or to enforce its rights under this EULA; or
|
|
65
|
+
3. required by law or by the order of a court or similar judicial or administrative body, provided that the User notifies the Company of such required disclosure promptly and in writing and cooperates with the Company, at the Company’s reasonable request and expense, in any lawful action to contest or limit the scope of such required disclosure.
|
|
66
|
+
4. User will return to the Company or destroy all tangible copies of Confidential Information in the User’s possession or control and permanently erase all electronic copies of Confidential Information promptly upon the expiration or termination of this EULA, whichever occurs first.
|
|
67
|
+
6. SUPPORT SERVICES
|
|
68
|
+
During the term of the EULA, the Company may provide support services directly to the User, or through the Authorised Reseller, such support terms being set out in the agreement between the User and the Authorised Reseller.
|
|
69
|
+
7. TERMINATION
|
|
70
|
+
1. Company may terminate this Agreement immediately whereby the User is in breach of the provisions of clause 3.2.
|
|
71
|
+
2. Notwithstanding the foregoing, any term or condition of the Agreement which by its sense or nature should be deemed to survive such termination shall so survive.
|
|
72
|
+
3. Without affecting any other right or remedy available to it, either party may terminate this agreement with immediate effect by giving written notice to the other party if:
|
|
73
|
+
1. the fees are payable directly to the Company, the other party fails to pay an amount due under this agreement on the due date for payment and remains in default not less than ten (10) days after being notified to make such payment;
|
|
74
|
+
2. the other party commits a material breach of any term of this agreement and (if such breach is remediable) fails to remedy that breach within a period of thirty (30) days after being notified in writing to do so;
|
|
75
|
+
3. the other party takes or has taken against it (other than in relation to a solvent restructuring) any step or action towards its entering bankruptcy, administration, provisional liquidation or any composition or arrangement with its creditors, applying to court for or obtaining a moratorium under Part A1 of the Insolvency Act 1986, being wound up (whether voluntarily or by order of the court), being struck off the register of companies, having a receiver appointed to any of its assets, or its entering a procedure in any jurisdiction with a similar effect to a procedure listed in this clause 7.3.3;
|
|
76
|
+
4. the other party suspends or ceases, or threatens to suspend or cease, carrying on business; or
|
|
77
|
+
5. the User enters into an agreement with an Authorised Reseller which subsequently terminates or is terminated.
|
|
78
|
+
4. Without affecting any other right or remedy available to it, either party may terminate this agreement on giving not less than one months' written notice
|
|
79
|
+
8. LIMITATION OF LIABILITY
|
|
80
|
+
1. The Software is provided by the Company on an 'as is' basis and accordingly all implied warranties terms or otherwise are hereby expressly excluded from the terms of this Agreement, including any terms relating to fitness for purpose, satisfactory quality or otherwise.
|
|
81
|
+
2. In no event shall the Company be liable to the User for any special, indirect, incidental or consequential damages, or any damages or costs due to any direct or indirect loss of profits, data, use or goodwill, personal or property damage resulting from or in connection with this EULA, the service, or the use or inability to use the service, regardless of the cause of action or the theory of liability, whether in tort (including negligence), contract, or otherwise, even if the Company has been notified of the likelihood of such damages.
|
|
82
|
+
3. Subject to clause 8.4, the maximum aggregate liability of the Company arising out of or in any way connected to this EULA whether in contract, tort (including negligence but excluding willful misconduct) or otherwise, shall be £10,000.
|
|
83
|
+
4. Neither party limits its liability (if any) to the other for: personal injury or death resulting from negligence; fraud; or any matter for which it would be illegal to exclude or to attempt to exclude its liability.
|
|
84
|
+
5. The Company cannot guarantee the accuracy and functionality of the output of the Services and their results and so the Company shall have no liability in relation to the output and any subsequent usage of any data from the output by the User.
|
|
85
|
+
9. FEES
|
|
86
|
+
1. User shall pay the fees in accordance with this clause 9 and any payment terms specified by the Company from time to time without set-off in respect of any liability of the Company.
|
|
87
|
+
2. Unless otherwise agreed with the Company, fees (and any expenses or other sums) payable under this Agreement are due at the point of sale. Payment confirmation will be provided after payment has been taken.
|
|
88
|
+
3. All fees, expenses or other sums payable under this Agreement are exclusive of any applicable value added tax or other applicable taxes or duties for which the User shall be additionally liable.
|
|
89
|
+
4. If any sum payable to the Company is not paid within 14 days after the due date the Company may suspend performance of its obligations and/or charge interest on a daily basis at the rate of 4% above the Bank of England's base rate from time to time in force, compounded quarterly, from the date for payment of that sum to the date of actual payment.
|
|
90
|
+
5. The Company shall be entitled to increase the fees at any time upon thirty (30) days' prior written notice to the User before the start of a new or renewed .
|
|
91
|
+
6. Where the User: (a) is participating in a Proof of Value; or (b) has purchased the Services through an Authorised Reseller of the Supplier this clause 9 shall not apply.
|
|
92
|
+
10. MISCELLANEOUS
|
|
93
|
+
1. Jurisdiction. This EULA and any dispute or claim arising out of it or in connection with it or its subject matter or formation (including non-contractual disputes or claims) shall be governed by and construed in accordance with the laws of England and Wales. Each Party irrevocably agrees that the courts of England have exclusive jurisdiction to any dispute or claim arising out of or in connection with this EULA or its subject matter or formation (including non-contractual disputes or claims).
|
|
94
|
+
2. No Partnership and Agency. The relationship between the parties is that of independent contractors and nothing in this Agreement shall be construed to create a partnership, joint venture, or agency relationship between the parties, nor authorise any Party to make or enter into any commitments for or on behalf of the other Party. Each Party confirms it is acting on its own behalf and not for the benefit of any other person. The parties acknowledge that the arrangements between them are non-exclusive. Nothing contained in this Agreement shall prohibit either of the parties from conducting business activities with other third parties.
|
|
95
|
+
3. Compliance with laws. You shall always comply with all international and domestic laws, ordinances, regulations, and statutes that are applicable to its purchase and use of the Services.
|
|
96
|
+
4. Severance. If any provision of this EULA is, for any reason, held to be invalid or unenforceable, the other provisions of this EULA will remain enforceable, and the invalid or unenforceable provision will be deemed modified so that it is valid and enforceable to the maximum extent permitted by law.
|
|
97
|
+
5. Waiver. No failure or delay by a Party to exercise any right or remedy provided under this Agreement or by law shall constitute a waiver of that or any other right or remedy, nor shall it prevent or restrict the further exercise of that or any other right or remedy. No single or partial exercise of such right or remedy shall prevent or restrict the further exercise of that or any other right or remedy.
|
|
98
|
+
6. Assignment. Neither Party shall assign, subcontract, delegate, or otherwise transfer this EULA, or its rights and obligations herein, without obtaining the prior written consent of the other Party, and any attempted assignment, subcontract, delegation, or transfer in violation of the foregoing will be null and void; provided, however, that the Company may assign this EULA in connection with a merger, acquisition, reorganization or sale of all or substantially all of its assets, or other operation of law, without the User’s consent.
|
|
99
|
+
7. Force Majeure. Any delay in the performance of any duties or obligations of either Party will not be considered a breach of this EULA if such delay is caused by a labor dispute, shortage of materials, fire, earthquake, flood, or any other event beyond the control of such Party, provided that such Party uses reasonable efforts, under the circumstances, to notify the other Party of the cause of such delay and to resume performance as soon as possible.
|
|
100
|
+
8. Variation. No modification of or amendment to this EULA, or any waiver of any rights under this EULA, will be effective unless in writing and signed by an officer of the Company.
|
|
101
|
+
9. Counterparts. This Agreement may be executed in any number of counterparts, each of which when executed shall constitute a duplicate original, but all the counterparts shall together constitute the one agreement.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
_vollo_rt.py,sha256=8XqNhO6lkigehyldyx1uqgnRSMs36jb8mqn2wo7W_CY,4177
|
|
2
|
+
vollo_rt/__init__.py,sha256=Yl8w3yHOgyRNE38nHj7d48FZlm7DdGXuBXj3k6UrCeY,20759
|
|
3
|
+
vollo_rt-27.0.0.dist-info/EULA.md,sha256=0EKZV204TUv5L2XPMBz5WYtXoszclG-7U09UEGrvX6U,20275
|
|
4
|
+
vollo_rt-27.0.0.dist-info/METADATA,sha256=w1CXbiOPqUiJORrI2yKVjDM9mzWUQmuLCZPhy9hyCh4,174
|
|
5
|
+
vollo_rt-27.0.0.dist-info/WHEEL,sha256=VyG4dJCdJcxE1baiVBm9NET3Nj7Wne1lZZq7UFNxRpg,97
|
|
6
|
+
vollo_rt-27.0.0.dist-info/top_level.txt,sha256=Dz8aD7eOptQIPlSZBC_UUoP42gZzlkvO1WiyYng7ytg,19
|
|
7
|
+
vollo_rt-27.0.0.dist-info/RECORD,,
|