Skip to content

Commit

Permalink
ML Activations (#34)
Browse files Browse the repository at this point in the history
* add ml-activations.typ plot using typst and cetz:0.2.2

* update readme table and include typst files in update-readme-table.py

* add render-typst.py script using new pdf_to_svg_png_compressed() in scripts/__init__.py

* Update render-tikz.py script to use pdf_to_svg_png_compressed() in scripts/__init__.py

* load Typst code in vite.config.ts if found
  • Loading branch information
janosh committed Apr 9, 2024
1 parent c52ee4f commit b6657c8
Show file tree
Hide file tree
Showing 13 changed files with 184 additions and 88 deletions.
Binary file added assets/ml-activations/ml-activations-hd.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/ml-activations/ml-activations.pdf
Binary file not shown.
Binary file added assets/ml-activations/ml-activations.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions assets/ml-activations/ml-activations.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
33 changes: 33 additions & 0 deletions assets/ml-activations/ml-activations.typ
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#import "@preview/cetz:0.2.2": canvas, plot, draw

#set page(width: auto, height: auto, margin: 3pt)

#let relu(x) = if x < 0 { 0 } else { x }
#let gelu(x) = 0.5 * x * (1 + calc.tanh(calc.sqrt(2 / calc.pi) * (x + 0.044715 * calc.pow(x,3))))
#let leaky_relu(x) = if x < 0 { 0.01 * x } else { x }
#let sigmoid(x) = 1 / (1 + calc.exp(-x))
#let tanh(x) = (calc.exp(x) - calc.exp(-x)) / (calc.exp(x) + calc.exp(-x))
#let size = (8, 5)

#canvas({
plot.plot(
size: size,
y-tick-step: 2,
x-tick-step: 2,
legend: "legend.inner-north-west",
{
plot.add-hline(0, style: (stroke: 0.5pt))
plot.add-vline(0, style: (stroke: 0.5pt))
for (key, (func, color)) in (
"ReLU": (relu, red),
"GELU": (gelu, blue),
"Leaky ReLU": (leaky_relu, green),
"Sigmoid": (sigmoid, orange),
"Tanh": (tanh, purple)
).pairs() {
plot.add(style: (stroke: color + 1.5pt), domain: (-4, 4), func, label: key)
}
}
)
draw.grid((0,0), size, stroke: 0.1pt)
})
17 changes: 17 additions & 0 deletions assets/ml-activations/ml-activations.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
title: Common Activation Functions in Machine Learning
tags:
- machine-learning
- neural-networks
- activation-functions
- deep-learning
description: >
Plot of common machine learning activation functions.
Includes the Rectified Linear Unit (ReLU), Gaussian Error Linear Unit (GELU),
Leaky ReLU, Sigmoid, and Hyperbolic Tangent (tanh) activation functions.
Activation functions introduce non-linearity into neural networks, enabling them to learn
complex patterns and relationships in data. The choice of activation function can have a
significant impact on the performance and convergence of a neural network.
ReLU is widely used due to its simplicity and ability to alleviate the vanishing gradient problem.
GELU and Leaky ReLU are variants of ReLU that address some of its limitations.
Sigmoid and tanh are classical activation functions that squash the input to a fixed range,
but they are less commonly used in modern deep learning architectures due to the vanishing gradient problem.
100 changes: 51 additions & 49 deletions readme.md

Large diffs are not rendered by default.

38 changes: 38 additions & 0 deletions scripts/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import os


def pdf_to_svg_png_compressed(pdf_path: str) -> str:
base_path = os.path.splitext(pdf_path)[0]

print("\n--- pdf-compressor ---")
os.system(f"pdf-compressor --inplace {base_path}.pdf")

print("Converting PDF to SVG and compressing")
if os.system(f"pdf2svg {base_path}.pdf {base_path}.svg") != 0:
print("pdf2svg failed, skipping SVG generation")
else:
svg_size = os.stat(f"{base_path}.svg").st_size
if svg_size > 500_000:
os.remove(f"{base_path}.svg")
else:
os.system(f"svgo --multipass {base_path}.svg")

# https://stackoverflow.com/q/52998331
if os.getenv("CI") == "true":
os.system(
"sudo sed -i '/disable ghostscript format types/,+6d' /etc/ImageMagick-6/policy.xml"
)

print("\n--- imagemagick: convert PDF to PNG ---")
os.system(f"convert -density 200 {base_path}.pdf {base_path}.png")
os.system(f"convert -density 400 {base_path}.pdf {base_path}-hd.png")

print("\n--- pngquant: compress ---")
os.system(f"pngquant 32 --skip-if-larger --ext .png --force {base_path}.png")
os.system(f"pngquant 32 --skip-if-larger --ext .png --force {base_path}-hd.png")

print("\n--- zopfli: compress ---")
os.system(f"zopflipng -y {base_path}.png {base_path}.png")
os.system(f"zopflipng -y {base_path}-hd.png {base_path}-hd.png")

return base_path
47 changes: 11 additions & 36 deletions scripts/render-tikz.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,28 @@
import subprocess
import sys

sys.path.append(".")

from scripts import pdf_to_svg_png_compressed

# Get name of directory containing the TeX file.
tex_file = sys.argv[1]
in_dir = os.path.dirname(os.path.abspath(tex_file))

# Get basepath of TeX file, i.e. path without extension.
basepath = os.path.splitext(tex_file)[0]
# Get base path of TeX file, i.e. path without extension.
base_path = os.path.splitext(tex_file)[0]
in_dir = os.path.dirname(tex_file)

print("Running latexmk to generate PDF from TeX file")
ret_val = subprocess.run(
["latexmk", "-silent", "-pdf", f"-jobname={basepath}", tex_file],
["latexmk", "-silent", "-pdf", f"-jobname={base_path}", tex_file],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
).returncode

if os.getenv("CI") == "true":
print("Detected CI=true")
if ret_val != 0:
with open(f"{basepath}.log", "r") as f:
with open(f"{base_path}.log", "r") as f:
print(f.read())
raise SystemExit(f"latexmk failed with return code {ret_val}. See log above.")

Expand All @@ -29,36 +33,7 @@
if file.endswith(("aux", "log", "fls", "fdb_latexmk")):
os.remove(f"{in_dir}/{file}")

print("\n--- pdf-compressor ---")
os.system(f"pdf-compressor --inplace {basepath}.pdf")

print("Converting PDF to SVG and compressing")
if os.system(f"pdf2svg {basepath}.pdf {basepath}.svg") != 0:
print("pdf2svg failed, skipping SVG generation")
else:
svg_size = os.stat(f"{basepath}.svg").st_size
if svg_size > 500_000:
os.remove(f"{basepath}.svg")
else:
os.system(f"svgo --multipass {basepath}.svg")

# https://stackoverflow.com/q/52998331
if os.getenv("CI") == "true":
os.system(
"sudo sed -i '/disable ghostscript format types/,+6d' /etc/ImageMagick-6/policy.xml"
)

print("\n--- imagemagick: convert PDF to PNG ---")
os.system(f"convert -density 200 {basepath}.pdf {basepath}.png")
os.system(f"convert -density 400 {basepath}.pdf {basepath}-hd.png")

print("\n--- pngquant: compress ---")
os.system(f"pngquant 32 --skip-if-larger --ext .png --force {basepath}.png")
os.system(f"pngquant 32 --skip-if-larger --ext .png --force {basepath}-hd.png")

print("\n--- zopfli: compress ---")
os.system(f"zopflipng -y {basepath}.png {basepath}.png")
os.system(f"zopflipng -y {basepath}-hd.png {basepath}-hd.png")
pdf_to_svg_png_compressed(f"{base_path}.pdf")

print("Update readme table listing all TikZ figures in assets/")
print("Update readme table listing all figures in assets/")
runpy.run_path("scripts/update-readme-table.py")
22 changes: 22 additions & 0 deletions scripts/render-typst.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import os
import runpy
import subprocess
import sys

sys.path.append(".")

from scripts import pdf_to_svg_png_compressed

# Get name of directory containing the Typst file.
input_file = sys.argv[1]

# Get base path of Typst file, i.e. path without extension.
base_path = os.path.splitext(input_file)[0]

print("Generating PDF from Typst file")
ret_val = subprocess.run(["typst", "compile", input_file]).returncode

pdf_to_svg_png_compressed(f"{base_path}.pdf")

print("Update readme table listing all figures in assets/")
runpy.run_path("scripts/update-readme-table.py")
4 changes: 2 additions & 2 deletions scripts/update-readme-table.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""Auto-update readme table listing all TikZ figures in assets/."""
"""Auto-update readme table listing all figures in assets/."""

import json
import os
Expand All @@ -13,7 +13,7 @@
with open(f"{ROOT}/site/package.json", "r") as file:
site_url = json.load(file)["homepage"]

tex_paths = sorted(glob(f"{TEX_DIR}/**/*.tex"))
tex_paths = sorted(glob(f"{TEX_DIR}/**/*.tex") + glob(f"{TEX_DIR}/**/*.typ"))

md_table = f"| {'&emsp;' * 22} | {'&emsp;' * 22} |\n| :---: | :---: |\n"

Expand Down
4 changes: 4 additions & 0 deletions site/src/lib/CodeBlock.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
import { CopyButton } from 'svelte-zoo'
hljs.registerLanguage(`latex`, latex)
// TODO highlight.js does not support Typst
// https://github.com/highlightjs/highlight.js/blob/main/SUPPORTED_LANGUAGES.md
// and won't unless someone contributes a grammar
// https://highlightjs.readthedocs.io/en/latest/language-requests.html
export let code: string
export let link: string
Expand Down
6 changes: 5 additions & 1 deletion site/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,11 @@ const tikz_figures = figure_dirs.map((slug) => {

const downloads = fs.readdirSync(`../assets/${slug}`)

const code = fs.readFileSync(`${figure_basename}.tex`, `utf8`)
// check tex file exists
const src_path = fs.existsSync(`${figure_basename}.tex`)
? `${figure_basename}.tex`
: `${figure_basename}.typ`
const code = fs.readFileSync(src_path, `utf-8`)

const { width, height } = image_dims(`${figure_basename}.png`)
const metadata = yaml.load(
Expand Down

0 comments on commit b6657c8

Please sign in to comment.