From 5a8fe7cdda712bfbfd8fa931dc476726fc97350c Mon Sep 17 00:00:00 2001 From: Umut Date: Tue, 22 Nov 2022 16:50:15 +0100 Subject: [PATCH] docs: document some of the new features, improve the parts of the old documentation --- README.md | 45 +++-- docs/SUMMARY.md | 10 +- docs/_static/rounded-tlu/10-bits-removed.png | Bin 0 -> 32696 bytes docs/_static/rounded-tlu/12-bits-removed.png | Bin 0 -> 27394 bytes docs/_static/rounded-tlu/4-bits-kept.png | Bin 0 -> 23737 bytes docs/_static/rounded-tlu/6-bits-kept.png | Bin 0 -> 27394 bytes docs/_static/rounded-tlu/relu.png | Bin 0 -> 39852 bytes docs/getting-started/compatibility.md | 20 +- docs/getting-started/exactness.md | 27 +++ docs/getting-started/performance.md | 104 ++++++++++ docs/getting-started/quick_start.md | 4 + docs/tutorial/direct_circuits.md | 83 ++++++++ docs/tutorial/formatting.md | 10 +- docs/tutorial/rounded_table_lookups.md | 183 ++++++++++++++++++ .../{table_lookup.md => table_lookups.md} | 0 docs/tutorial/tagging.md | 56 ++++++ docs/tutorial/virtual_circuits.md | 54 ++++++ 17 files changed, 552 insertions(+), 44 deletions(-) create mode 100644 docs/_static/rounded-tlu/10-bits-removed.png create mode 100644 docs/_static/rounded-tlu/12-bits-removed.png create mode 100644 docs/_static/rounded-tlu/4-bits-kept.png create mode 100644 docs/_static/rounded-tlu/6-bits-kept.png create mode 100644 docs/_static/rounded-tlu/relu.png create mode 100644 docs/getting-started/exactness.md create mode 100644 docs/getting-started/performance.md create mode 100644 docs/tutorial/direct_circuits.md create mode 100644 docs/tutorial/rounded_table_lookups.md rename docs/tutorial/{table_lookup.md => table_lookups.md} (100%) create mode 100644 docs/tutorial/tagging.md create mode 100644 docs/tutorial/virtual_circuits.md diff --git a/README.md b/README.md index 8fb9a98cc..d91657543 100644 --- a/README.md +++ b/README.md @@ -71,26 +71,6 @@ You can find more detailed installation instructions in [installing.md](docs/get ```python import concrete.numpy as cnp -@cnp.compiler({"x": "encrypted", "y": "encrypted"}) -def add(x, y): - return x + y - -inputset = [(2, 3), (0, 0), (1, 6), (7, 7), (7, 1), (3, 2), (6, 1), (1, 7), (4, 5), (5, 4)] - -print(f"Compiling...") -circuit = add.compile(inputset) - -examples = [(3, 4), (1, 2), (7, 7), (0, 0)] -for example in examples: - result = circuit.encrypt_run_decrypt(*example) - print(f"Evaluation of {' + '.join(map(str, example))} homomorphically = {result}") -``` - -if you have a function object that you cannot decorate, you can use the explicit `Compiler` API instead - -```python -import concrete.numpy as cnp - def add(x, y): return x + y @@ -100,6 +80,31 @@ inputset = [(2, 3), (0, 0), (1, 6), (7, 7), (7, 1), (3, 2), (6, 1), (1, 7), (4, print(f"Compiling...") circuit = compiler.compile(inputset) +print(f"Generating keys...") +circuit.keygen() + +examples = [(3, 4), (1, 2), (7, 7), (0, 0)] +for example in examples: + encrypted_example = circuit.encrypt(*example) + encrypted_result = circuit.run(encrypted_example) + result = circuit.decrypt(encrypted_result) + print(f"Evaluation of {' + '.join(map(str, example))} homomorphically = {result}") +``` + +or if you have a simple function that you can decorate, and you don't care about explicit steps of key generation, encryption, evaluation and decryption: + +```python +import concrete.numpy as cnp + +@cnp.compiler({"x": "encrypted", "y": "encrypted"}) +def add(x, y): + return x + y + +inputset = [(2, 3), (0, 0), (1, 6), (7, 7), (7, 1), (3, 2), (6, 1), (1, 7), (4, 5), (5, 4)] + +print(f"Compiling...") +circuit = add.compile(inputset) + examples = [(3, 4), (1, 2), (7, 7), (0, 0)] for example in examples: result = circuit.encrypt_run_decrypt(*example) diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md index c21c890f5..0b3052e7d 100644 --- a/docs/SUMMARY.md +++ b/docs/SUMMARY.md @@ -7,14 +7,20 @@ * [Installation](getting-started/installing.md) * [Quick Start](getting-started/quick\_start.md) * [Compatibility](getting-started/compatibility.md) +* [Exactness](getting-started/exactness.md) +* [Performance](getting-started/performance.md) ## Tutorials * [Decorator](tutorial/decorator.md) +* [Formatting](tutorial/formatting.md) +* [Tagging](tutorial/tagging.md) * [Extensions](tutorial/extensions.md) -* [Table Lookups](tutorial/table\_lookup.md) +* [Table Lookups](tutorial/table\_lookups.md) +* [Rounded Table Lookups](tutorial/rounded\_table\_lookups.md) * [Floating Points](tutorial/floating\_points.md) -* [Format](tutorial/formatting.md) +* [Virtual Circuits](tutorial/virtual\_circuits.md) +* [Direct Circuits](tutorial/direct\_circuits.md) ## How To diff --git a/docs/_static/rounded-tlu/10-bits-removed.png b/docs/_static/rounded-tlu/10-bits-removed.png new file mode 100644 index 0000000000000000000000000000000000000000..1a405437bae86bebe3425d965c0c2dcd5f279439 GIT binary patch literal 32696 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 z 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 w4E~Ln#pgiBUn3?&n*J6dG6( literal 0 HcmV?d00001 diff --git a/docs/_static/rounded-tlu/12-bits-removed.png b/docs/_static/rounded-tlu/12-bits-removed.png new file mode 100644 index 0000000000000000000000000000000000000000..d1a36f841e2e9ae6f99d4f57389ee58e0ec51224 GIT binary patch literal 27394 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 K5)T>u{=We4i+<7o literal 0 HcmV?d00001 diff --git a/docs/_static/rounded-tlu/6-bits-kept.png b/docs/_static/rounded-tlu/6-bits-kept.png new file mode 100644 index 0000000000000000000000000000000000000000..d1a36f841e2e9ae6f99d4f57389ee58e0ec51224 GIT binary patch literal 27394 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 kv*w8o!vE=F?~M41;`;+d2VE5g(OQiROn=D#{_= WARMUP: + timings[n].append(tlu_time - base_time) + print(f"Sample #{i - WARMUP + 1} took {timings[n][-1] * 1000:.3f}ms") + +print() +for n, times in timings.items(): + print(f"{n}-bits -> {np.mean(times) * 1000:.3f}ms") +``` + +{% hint style="info" %} +Concrete Numpy automatically parallelize execution if TLUs are applied to tensors. +{% endhint %} diff --git a/docs/getting-started/quick_start.md b/docs/getting-started/quick_start.md index d93ddd96e..efc073a99 100644 --- a/docs/getting-started/quick_start.md +++ b/docs/getting-started/quick_start.md @@ -63,6 +63,10 @@ It should be an iterable, yielding tuples of the same length as the number of ar inputset = [(2, 3), (0, 0), (1, 6), (7, 7), (7, 1)] ``` +{% hint style="warning" %} +All inputs in the inputset will be evaluated in the graph, which takes time. If you're experiencing long compilation times, consider providing a smaller inputset. +{% endhint %} + ## Compiling the function You can use the `compile` method of a `Compiler` class with an inputset to perform the compilation and get the resulting circuit back: diff --git a/docs/tutorial/direct_circuits.md b/docs/tutorial/direct_circuits.md new file mode 100644 index 000000000..53e0b7ef0 --- /dev/null +++ b/docs/tutorial/direct_circuits.md @@ -0,0 +1,83 @@ +# Direct Circuits + +{% hint style="warning" %} +Direct circuits are still experimental, and it's very easy to shoot yourself in the foot (e.g., no overflow checks, no type coercion) while using them so utilize them with care. +{% endhint %} + +For some applications, data types of inputs, intermediate values and outputs are known (e.g., for manipulating bytes, you would want to use uint8). For such cases, using inputsets to determine bounds are not necessary, or even error-prone. Therefore, another interface for defining such circuits, is introduced: + +```python +import concrete.numpy as cnp + +@cnp.circuit({"x": "encrypted"}) +def circuit(x: cnp.uint8): + return x + 42 + +assert circuit.encrypt_run_decrypt(10) == 52 +``` + +There are a few differences between direct circuits and traditional circuits though: + +- You need to remember that resulting dtype for each operation will be determined by its inputs. This can lead to some unexpected results if you're not careful (e.g., if you do `-x` where `x: cnp.uint8`, you'll not get the negative value as the result will be `cnp.uint8` as well) +- You need to use cnp types in `.astype(...)` calls (e.g., `np.sqrt(x).astype(cnp.uint4)`). This is because there are no inputset evaluation, so cannot determine the bit-width of the output. +- You need to specify the resulting data type in [univariate](./extensions.md#cnpunivariatefunction) extension (e.g., `cnp.univariate(function, outputs=cnp.uint4)(x)`), because of the same reason as above. +- You need to be careful with overflows. With inputset evaluation, you'll get bigger bit-widths but no overflows, with direct definition, you're responsible to ensure there aren't any overflows! + +Let's go over a more complicated example to see how direct circuits behave: + +```python +import concrete.numpy as cnp +import numpy as np + +def square(value): + return value ** 2 + +@cnp.circuit({"x": "encrypted", "y": "encrypted"}) +def circuit(x: cnp.uint8, y: cnp.int2): + a = x + 10 + b = y + 10 + + c = np.sqrt(a).round().astype(cnp.uint4) + d = cnp.univariate(square, outputs=cnp.uint8)(b) + + return d - c + +print(circuit) +``` +prints +``` +%0 = x # EncryptedScalar +%1 = y # EncryptedScalar +%2 = 10 # ClearScalar +%3 = add(%0, %2) # EncryptedScalar +%4 = 10 # ClearScalar +%5 = add(%1, %4) # EncryptedScalar +%6 = subgraph(%3) # EncryptedScalar +%7 = square(%5) # EncryptedScalar +%8 = subtract(%7, %6) # EncryptedScalar +return %8 + +Subgraphs: + + %6 = subgraph(%3): + + %0 = input # EncryptedScalar + %1 = sqrt(%0) # EncryptedScalar + %2 = around(%1, decimals=0) # EncryptedScalar + %3 = astype(%2) # EncryptedScalar + return %3 +``` +And here is the breakdown of assigned data types: +``` +%0 is uint8 because it's specified in the definition +%1 is int2 because it's specified in the definition +%2 is uint4 because it's the constant 10 +%3 is uint8 because it's the addition between uint8 and uint4 +%4 is uint4 because it's the constant 10 +%5 is int4 because it's the addition between int2 and uint4 +%6 is uint4 because it's specified in astype +%7 is uint8 because it's specified in univariate +%8 is uint8 because it's subtraction between uint8 and uint4 +``` + +As you can see, `%8` is subtraction of two unsigned values, and it's unsigned as well. In an overflow condition where `c > d`, it'll result in undefined behavior. diff --git a/docs/tutorial/formatting.md b/docs/tutorial/formatting.md index 7c11e8350..9b1e4d56f 100644 --- a/docs/tutorial/formatting.md +++ b/docs/tutorial/formatting.md @@ -1,8 +1,4 @@ -# Format - -Sometimes, it can be useful to print circuits. We provide methods to just do that. - -## Formatting +# Formatting You can convert your compiled circuit into its textual representation by converting it to string: @@ -17,3 +13,7 @@ If you just want to see the output on your terminal, you can directly print it a ```python print(circuit) ``` + +{% hint style="warning" %} +Formatting is just for debugging. It's not possible to serialize the circuit back from its textual representation. See [How to Deploy](../howto/deploy.md) if that's your goal. +{% endhint %} diff --git a/docs/tutorial/rounded_table_lookups.md b/docs/tutorial/rounded_table_lookups.md new file mode 100644 index 000000000..7a14b669d --- /dev/null +++ b/docs/tutorial/rounded_table_lookups.md @@ -0,0 +1,183 @@ +# Rounded Table Lookups + +{% hint style="warning" %} +Rounded table lookups are only available in [virtual circuits](./virtual_circuits.md) for the time being. +{% endhint %} + +Table lookups have a strict constraint on number of bits they support. This can be quite limiting, especially if you don't need the exact precision. + +To overcome such shortcomings, rounded table lookup operation is introduced. It's a way to extract most significant bits of a large integer and then applying the table lookup to those bits. + +Imagine you have an 8-bit value, but you want to have a 5-bit table lookup, you can call `cnp.round_bit_pattern(input, lsbs_to_remove=3)` and use the value you get in the table lookup. + +In Python, evaluation will work like the following: +``` +0b_0000_0000 => 0b_0000_0000 +0b_0000_0001 => 0b_0000_0000 +0b_0000_0010 => 0b_0000_0000 +0b_0000_0011 => 0b_0000_0000 +0b_0000_0100 => 0b_0000_1000 +0b_0000_0101 => 0b_0000_1000 +0b_0000_0110 => 0b_0000_1000 +0b_0000_0111 => 0b_0000_1000 + +0b_1010_0000 => 0b_1010_0000 +0b_1010_0001 => 0b_1010_0000 +0b_1010_0010 => 0b_1010_0000 +0b_1010_0011 => 0b_1010_0000 +0b_1010_0100 => 0b_1010_1000 +0b_1010_0101 => 0b_1010_1000 +0b_1010_0110 => 0b_1010_1000 +0b_1010_0111 => 0b_1010_1000 + +0b_1010_1000 => 0b_1010_1000 +0b_1010_1001 => 0b_1010_1000 +0b_1010_1010 => 0b_1010_1000 +0b_1010_1011 => 0b_1010_1000 +0b_1010_1100 => 0b_1011_0000 +0b_1010_1101 => 0b_1011_0000 +0b_1010_1110 => 0b_1011_0000 +0b_1010_1111 => 0b_1011_0000 + +0b_1011_1000 => 0b_1011_1000 +0b_1011_1001 => 0b_1011_1000 +0b_1011_1010 => 0b_1011_1000 +0b_1011_1011 => 0b_1011_1000 +0b_1011_1100 => 0b_1100_0000 +0b_1011_1101 => 0b_1100_0000 +0b_1011_1110 => 0b_1100_0000 +0b_1011_1111 => 0b_1100_0000 +``` + +and during homomorphic execution, it'll be converted like this: +``` +0b_0000_0000 => 0b_00000 +0b_0000_0001 => 0b_00000 +0b_0000_0010 => 0b_00000 +0b_0000_0011 => 0b_00000 +0b_0000_0100 => 0b_00001 +0b_0000_0101 => 0b_00001 +0b_0000_0110 => 0b_00001 +0b_0000_0111 => 0b_00001 + +0b_1010_0000 => 0b_10100 +0b_1010_0001 => 0b_10100 +0b_1010_0010 => 0b_10100 +0b_1010_0011 => 0b_10100 +0b_1010_0100 => 0b_10101 +0b_1010_0101 => 0b_10101 +0b_1010_0110 => 0b_10101 +0b_1010_0111 => 0b_10101 + +0b_1010_1000 => 0b_10101 +0b_1010_1001 => 0b_10101 +0b_1010_1010 => 0b_10101 +0b_1010_1011 => 0b_10101 +0b_1010_1100 => 0b_10110 +0b_1010_1101 => 0b_10110 +0b_1010_1110 => 0b_10110 +0b_1010_1111 => 0b_10110 + +0b_1011_1000 => 0b_10111 +0b_1011_1001 => 0b_10111 +0b_1011_1010 => 0b_10111 +0b_1011_1011 => 0b_10111 +0b_1011_1100 => 0b_11000 +0b_1011_1101 => 0b_11000 +0b_1011_1110 => 0b_11000 +0b_1011_1111 => 0b_11000 +``` + +and then a modified table lookup would be applied to the resulting 5-bits. + +Here is a concrete example, let's say you want to apply ReLU to an 18-bit value. Let's see what the original ReLU looks like first: + +```python +import matplotlib.pyplot as plt + +def relu(x): + return x if x >= 0 else 0 + +xs = range(-100_000, 100_000) +ys = [relu(x) for x in xs] + +plt.plot(xs, ys) +plt.show() +``` + +![](../_static/rounded-tlu/relu.png) + +Input range is [-100_000, 100_000), which means 18-bit table lookups are required, but they are not supported yet, you can apply rounding operation to the input before passing it to `ReLU` function: + +```python +import concrete.numpy as cnp +import matplotlib.pyplot as plt +import numpy as np + +def relu(x): + return x if x >= 0 else 0 + +@cnp.compiler({"x": "encrypted"}) +def f(x): + x = cnp.round_bit_pattern(x, lsbs_to_remove=10) + return cnp.univariate(relu)(x) + +inputset = [-100_000, (100_000 - 1)] +circuit = f.compile(inputset, enable_unsafe_features=True, virtual=True) + +xs = range(-100_000, 100_000) +ys = [circuit.encrypt_run_decrypt(x) for x in xs] + +plt.plot(xs, ys) +plt.show() +``` + +in this case we've removed 10 least significant bits of the input and then applied ReLU function to this value to get: + +![](../_static/rounded-tlu/10-bits-removed.png) + +which is close enough to original ReLU for some cases. If your application is more flexible, you could remove more bits, let's say 12 to get: + +![](../_static/rounded-tlu/12-bits-removed.png) + +This is very useful, but in some cases, you don't know how many bits your input have, so it's not reliable to specify `lsbs_to_remove` manually. For this reason, `AutoRounder` class is introduced. + +```python +import concrete.numpy as cnp +import matplotlib.pyplot as plt +import numpy as np + +rounder = cnp.AutoRounder(target_msbs=6) + +def relu(x): + return x if x >= 0 else 0 + +@cnp.compiler({"x": "encrypted"}) +def f(x): + x = cnp.round_bit_pattern(x, lsbs_to_remove=rounder) + return cnp.univariate(relu)(x) + +inputset = [-100_000, (100_000 - 1)] +cnp.AutoRounder.adjust(f, inputset) # alternatively, you can use `auto_adjust_rounders=True` below +circuit = f.compile(inputset, enable_unsafe_features=True, virtual=True) + +xs = range(-100_000, 100_000) +ys = [circuit.encrypt_run_decrypt(x) for x in xs] + +plt.plot(xs, ys) +plt.show() +``` + +`AutoRounder`s allow you to set how many of the most significant bits to keep, but they need to be adjusted using an inputset to determine how many of the least significant bits to remove. This can be done manually using `cnp.AutoRounder.adjust(function, inputset)`, or by setting `auto_adjust_rounders` to `True` during compilation. + +In the example above, `6` of the most significant bits are kept to get: + +![](../_static/rounded-tlu/6-bits-kept.png) + +You can adjust `target_msbs` depending on your requirements. If you set it to `4` for example, you'd get: + +![](../_static/rounded-tlu/4-bits-kept.png) + +{% hint style="warning" %} +`AutoRounder`s should be defined outside the function being compiled. They are used to store the result of aqdjustment process, so they shouldn't be created each time the function is called. +{% endhint %} diff --git a/docs/tutorial/table_lookup.md b/docs/tutorial/table_lookups.md similarity index 100% rename from docs/tutorial/table_lookup.md rename to docs/tutorial/table_lookups.md diff --git a/docs/tutorial/tagging.md b/docs/tutorial/tagging.md new file mode 100644 index 000000000..280893356 --- /dev/null +++ b/docs/tutorial/tagging.md @@ -0,0 +1,56 @@ +# Tagging + +When you have big circuits, keeping track of which node corresponds to which part of your code becomes very hard. Tagging system could simplify such situations: + +```python +def g(z): + with cnp.tag("def"): + a = 120 - z + b = a // 4 + return b + + +def f(x): + with cnp.tag("abc"): + x = x * 2 + with cnp.tag("foo"): + y = x + 42 + z = np.sqrt(y).astype(np.int64) + + return g(z + 3) * 2 +``` + +when you compile `f` with inputset of `range(10)`, you get the following graph: + +``` + %0 = x # EncryptedScalar ∈ [0, 9] + %1 = 2 # ClearScalar ∈ [2, 2] @ abc + %2 = multiply(%0, %1) # EncryptedScalar ∈ [0, 18] @ abc + %3 = 42 # ClearScalar ∈ [42, 42] @ abc.foo + %4 = add(%2, %3) # EncryptedScalar ∈ [42, 60] @ abc.foo + %5 = subgraph(%4) # EncryptedScalar ∈ [6, 7] @ abc + %6 = 3 # ClearScalar ∈ [3, 3] + %7 = add(%5, %6) # EncryptedScalar ∈ [9, 10] + %8 = 120 # ClearScalar ∈ [120, 120] @ def + %9 = subtract(%8, %7) # EncryptedScalar ∈ [110, 111] @ def +%10 = 4 # ClearScalar ∈ [4, 4] @ def +%11 = floor_divide(%9, %10) # EncryptedScalar ∈ [27, 27] @ def +%12 = 2 # ClearScalar ∈ [2, 2] +%13 = multiply(%11, %12) # EncryptedScalar ∈ [54, 54] +return %13 + +Subgraphs: + + %5 = subgraph(%4): + + %0 = input # EncryptedScalar @ abc.foo + %1 = sqrt(%0) # EncryptedScalar @ abc + %2 = astype(%1, dtype=int_) # EncryptedScalar @ abc + return %2 +``` + +and if you get an error, you'll precisely see where the error occurred (e.g., which layer of the neural network, if you tag layers). + +{% hint style="info" %} +In the future, we're planning to use tags for other features as well (e.g., to measure performance of tagged regions), so it's a good idea to start utilizing them for big circuits. +{% endhint %} diff --git a/docs/tutorial/virtual_circuits.md b/docs/tutorial/virtual_circuits.md new file mode 100644 index 000000000..b3b417ebf --- /dev/null +++ b/docs/tutorial/virtual_circuits.md @@ -0,0 +1,54 @@ +# Virtual Circuits + +During development, speed of homomorphic execution is a big blocker for fast prototyping. Furthermore, it might be desirable to experiment with more bit-widths, even though they are not supported yet, to get insights about the requirements of your system (e.g., we would have an XYZ model with 95% accuracy if we have 25-bits). + +To simplify this process, we've introduces virtual circuits: + +```python +import concrete.numpy as cnp +import numpy as np + +@cnp.compiler({"x": "encrypted"}) +def f(x): + return np.sqrt(x * 100_000).round().astype(np.int64) + +inputset = range(100_000, 101_000) +circuit = f.compile(inputset, enable_unsafe_features=True, virtual=True) + +print(circuit) +print(circuit.encrypt_run_decrypt(100_500), "~=", np.sqrt(100_500 * 100_000)) +``` + +prints + +``` +%0 = x # EncryptedScalar ∈ [100000, 100999] +%1 = 100000 # ClearScalar ∈ [100000, 100000] +%2 = multiply(%0, %1) # EncryptedScalar ∈ [10000000000, 10099900000] +%3 = subgraph(%2) # EncryptedScalar ∈ [100000, 100498] +return %3 + +Subgraphs: + + %3 = subgraph(%2): + + %0 = input # EncryptedScalar + %1 = sqrt(%0) # EncryptedScalar + %2 = around(%1, decimals=0) # EncryptedScalar + %3 = astype(%2, dtype=int_) # EncryptedScalar + return %3 + +100250 ~= 100249.6882788171 +``` + +and it doesn't perform any homomorphic computation. It just simulates execution. + +Keyword arguments `enable_unsafe_features=True` and `virtual=True` passed to `compile` are configuration options. `virtaul=True` enables makes the circuit virtual, and because virtual circuits are highly experimental, unsafe features must be enabled using `enable_unsafe_features=True` to utilize virtual circuits. See [How to Configure](../howto/configure.md) to learn more about configuration options. + +{% hint style="info" %} +Virtual circuits still check for operational constraints and type constraints. Which means you cannot have floating points, or unsupported operations. They just ignore bit-width constraints. +{% endhint %} + +{% hint style="warning" %} +Virtual circuits are still experimental, and they don't properly consider [error probability](../getting-started/exactness.md) for example. That's why you need to enable unsafe features to use them. Use them with care! +{% endhint %}