Skip to content

Commit f25034d

Browse files
ykhrustalevclaude
andauthored
Add GitHub workflow for Python formatting checks (#10)
Co-authored-by: Claude <noreply@anthropic.com>
1 parent 98fe0dd commit f25034d

File tree

8 files changed

+118
-50
lines changed

8 files changed

+118
-50
lines changed

.github/workflows/check_python.yml

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
name: Check Python
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
9+
concurrency:
10+
group: ${{ github.workflow }}-${{ github.ref }}
11+
cancel-in-progress: true
12+
13+
jobs:
14+
check:
15+
runs-on: ubuntu-latest
16+
steps:
17+
- uses: actions/create-github-app-token@v2
18+
id: app-token
19+
with:
20+
app-id: ${{ secrets.AUTH_APP_ID }}
21+
private-key: ${{ secrets.AUTH_APP_SECRET_KEY }}
22+
owner: ${{ github.repository_owner }}
23+
- uses: actions/checkout@v5
24+
with:
25+
token: ${{ steps.app-token.outputs.token }}
26+
persist-credentials: false
27+
ref: ${{ github.event.inputs.branch }}
28+
submodules: recursive
29+
lfs: true
30+
fetch-depth: 0
31+
32+
- uses: astral-sh/setup-uv@v4
33+
- run: uv python install 3.12
34+
- run: git config --global url."https://x-access-token:${{ steps.app-token.outputs.token }}@github.com/".insteadOf "ssh://git@github.com/"
35+
- run: uv sync --extra dev
36+
- run: uv run ruff format --check src tests
37+
- run: uv run ruff check src tests

src/liquidonnx/builder_base.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -94,9 +94,7 @@ def add_initializer(self, name: str, tensor: np.ndarray, dtype=None):
9494
tensor = tensor.astype(dtype)
9595
self.initializers.append(numpy_helper.from_array(tensor, name))
9696

97-
def add_value_info(
98-
self, name: str, elem_type: int, shape: list[int | str]
99-
) -> None:
97+
def add_value_info(self, name: str, elem_type: int, shape: list[int | str]) -> None:
10098
"""Add shape annotation for an intermediate tensor.
10199
102100
Args:
@@ -218,7 +216,9 @@ def make_gelu(self, input_name: str, path: str, approximate: str = "tanh") -> st
218216
Returns:
219217
Output name "{path}/Gelu/output_0"
220218
"""
221-
return self.make_node("Gelu", [input_name], [self._output_name(path, "Gelu")], approximate=approximate)
219+
return self.make_node(
220+
"Gelu", [input_name], [self._output_name(path, "Gelu")], approximate=approximate
221+
)
222222

223223
def make_layernorm(
224224
self,
@@ -334,9 +334,7 @@ def make_linear(
334334

335335
return matmul_out
336336

337-
def make_slice_last_n(
338-
self, input_name: str, n_elements: str, path: str, axis: int = 2
339-
) -> str:
337+
def make_slice_last_n(self, input_name: str, n_elements: str, path: str, axis: int = 2) -> str:
340338
"""Slice last N elements along axis (dynamic N).
341339
342340
Args:
@@ -349,7 +347,9 @@ def make_slice_last_n(
349347
Output name "{path}/Slice/output_0"
350348
"""
351349
neg_n = self.make_mul(n_elements, self.get_constant(-1), self._output_name(path, "Mul"))
352-
start = self.make_unsqueeze(neg_n, self.get_constant([0]), self._output_name(path, "Unsqueeze"))
350+
start = self.make_unsqueeze(
351+
neg_n, self.get_constant([0]), self._output_name(path, "Unsqueeze")
352+
)
353353

354354
return self.make_slice(
355355
input_name,

src/liquidonnx/external_data.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,7 @@
2424
def _model_uses_external_data(model: onnx.ModelProto) -> bool:
2525
"""Check if any tensor in the model uses external data."""
2626
for tensor in model.graph.initializer:
27-
if (
28-
tensor.HasField("data_location")
29-
and tensor.data_location == onnx.TensorProto.EXTERNAL
30-
):
27+
if tensor.HasField("data_location") and tensor.data_location == onnx.TensorProto.EXTERNAL:
3128
return True
3229
return False
3330

@@ -143,8 +140,7 @@ def split_external_data(
143140
current_chunk_file.close()
144141
if current_chunk_size > 0:
145142
logger.info(
146-
f" Chunk {chunk_idx}: {current_chunk_path.name} "
147-
f"({current_chunk_size / 1e9:.2f} GB)"
143+
f" Chunk {chunk_idx}: {current_chunk_path.name} ({current_chunk_size / 1e9:.2f} GB)"
148144
)
149145
else:
150146
# Remove empty file

src/liquidonnx/lfm2/builder.py

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,9 @@ def from_hf_config(cls, config) -> "LFM2Config":
5858
if multiplier is not None:
5959
intermediate_size = int(multiplier * intermediate_size)
6060
multiple_of = getattr(config, "block_multiple_of", 256)
61-
intermediate_size = multiple_of * ((intermediate_size + multiple_of - 1) // multiple_of)
61+
intermediate_size = multiple_of * (
62+
(intermediate_size + multiple_of - 1) // multiple_of
63+
)
6264

6365
return cls(
6466
hidden_size=config.hidden_size,
@@ -83,7 +85,9 @@ class LFM2Builder(ONNXBuilderBase):
8385
- Fused Microsoft operators (SimplifiedLayerNormalization, RotaryEmbedding, GroupQueryAttention)
8486
"""
8587

86-
def __init__(self, config: LFM2Config, use_integrated_rope: bool = False, vl_naming: bool = False):
88+
def __init__(
89+
self, config: LFM2Config, use_integrated_rope: bool = False, vl_naming: bool = False
90+
):
8791
"""
8892
Args:
8993
config: Model configuration
@@ -819,7 +823,10 @@ def build_lm_head(self, hidden_state: str) -> str:
819823
self.add_initializer(final_norm_weight, self.weights["model.embedding_norm.weight"])
820824
# Community uses SkipLayerNorm as node name suffix
821825
normed = self.make_skip_layernorm(
822-
hidden_state, hidden_state, final_norm_weight, final_norm_output,
826+
hidden_state,
827+
hidden_state,
828+
final_norm_weight,
829+
final_norm_output,
823830
name=f"/model/layers.{num_layers}/final_norm_layernorm/SkipLayerNorm",
824831
)
825832

@@ -843,12 +850,10 @@ def build_value_info(self):
843850
the community model format.
844851
"""
845852
H = self.config.hidden_size
846-
nh = self.config.num_attention_heads
847853
nkv = self.config.num_key_value_heads
848854
hd = self.head_dim
849855
kv_hidden = nkv * hd
850856
intermediate = self.config.intermediate_size
851-
L = self.config.conv_L_cache
852857
num_layers = self.config.num_hidden_layers
853858
mask_prefix = "/model/attn_mask_reformat/attn_mask_subgraph"
854859

@@ -872,7 +877,9 @@ def build_value_info(self):
872877

873878
# === Embedding output ===
874879
self.add_value_info(
875-
"/model/embed_tokens/Gather/output_0", TensorProto.FLOAT, ["batch_size", "sequence_length", H]
880+
"/model/embed_tokens/Gather/output_0",
881+
TensorProto.FLOAT,
882+
["batch_size", "sequence_length", H],
876883
)
877884

878885
# === Per-layer outputs ===
@@ -900,16 +907,24 @@ def build_value_info(self):
900907
["batch_size", 3 * H, "sequence_length"],
901908
)
902909
self.add_value_info(
903-
f"{prefix}/conv/Split/output_0", TensorProto.FLOAT, ["batch_size", H, "sequence_length"]
910+
f"{prefix}/conv/Split/output_0",
911+
TensorProto.FLOAT,
912+
["batch_size", H, "sequence_length"],
904913
)
905914
self.add_value_info(
906-
f"{prefix}/conv/Split/output_1", TensorProto.FLOAT, ["batch_size", H, "sequence_length"]
915+
f"{prefix}/conv/Split/output_1",
916+
TensorProto.FLOAT,
917+
["batch_size", H, "sequence_length"],
907918
)
908919
self.add_value_info(
909-
f"{prefix}/conv/Split/output_2", TensorProto.FLOAT, ["batch_size", H, "sequence_length"]
920+
f"{prefix}/conv/Split/output_2",
921+
TensorProto.FLOAT,
922+
["batch_size", H, "sequence_length"],
910923
)
911924
self.add_value_info(
912-
f"{prefix}/conv/Mul_1/output_0", TensorProto.FLOAT, ["batch_size", H, "sequence_length"]
925+
f"{prefix}/conv/Mul_1/output_0",
926+
TensorProto.FLOAT,
927+
["batch_size", H, "sequence_length"],
913928
)
914929
self.add_value_info(
915930
f"{prefix}/conv/Conv_Input/output_0",
@@ -921,11 +936,17 @@ def build_value_info(self):
921936
conv_gather_name = "Gather_1" if self.vl_naming else "Gather_for_slice"
922937
self.add_value_info(f"{prefix}/conv/split_sizes", TensorProto.INT64, [3])
923938
self.add_value_info(f"{prefix}/conv/{shape_name}/output_0", TensorProto.INT64, [3])
924-
self.add_value_info(f"{prefix}/conv/{conv_gather_name}/output_0", TensorProto.INT64, [])
939+
self.add_value_info(
940+
f"{prefix}/conv/{conv_gather_name}/output_0", TensorProto.INT64, []
941+
)
925942
self.add_value_info(f"{prefix}/conv/Neg_Seq_Len/output_0", TensorProto.INT64, [])
926-
self.add_value_info(f"{prefix}/conv/Unsqueeze_starts/output_0", TensorProto.INT64, [1])
927943
self.add_value_info(
928-
f"{prefix}/conv/Mul_2/output_0", TensorProto.FLOAT, ["batch_size", H, "sequence_length"]
944+
f"{prefix}/conv/Unsqueeze_starts/output_0", TensorProto.INT64, [1]
945+
)
946+
self.add_value_info(
947+
f"{prefix}/conv/Mul_2/output_0",
948+
TensorProto.FLOAT,
949+
["batch_size", H, "sequence_length"],
929950
)
930951
self.add_value_info(
931952
f"{prefix}/conv/Transpose_2/output_0",
@@ -1062,7 +1083,9 @@ def build_value_info(self):
10621083
TensorProto.FLOAT,
10631084
["batch_size", "sequence_length", H],
10641085
)
1065-
self.add_value_info("/lm_head/Transpose/output_0", TensorProto.FLOAT, [H, self.config.vocab_size])
1086+
self.add_value_info(
1087+
"/lm_head/Transpose/output_0", TensorProto.FLOAT, [H, self.config.vocab_size]
1088+
)
10661089

10671090
def load_weights(self, model_path: str):
10681091
"""Load weights from HuggingFace model."""

src/liquidonnx/lfm2_moe/builder.py

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1354,7 +1354,9 @@ def build_lm_head(self, hidden_state: str) -> str:
13541354
# Community naming: model.layers.{num_layers}.final_norm_layernorm.weight
13551355
num_layers = self.config.num_hidden_layers
13561356
final_norm_weight = f"model.layers.{num_layers}.final_norm_layernorm.weight"
1357-
final_norm_output = f"/model/layers.{num_layers}/final_norm_layernorm/SkipLayerNorm/output_0"
1357+
final_norm_output = (
1358+
f"/model/layers.{num_layers}/final_norm_layernorm/SkipLayerNorm/output_0"
1359+
)
13581360

13591361
self.add_initializer(final_norm_weight, self.weights["model.embedding_norm.weight"])
13601362
normed = self.make_skip_layernorm(
@@ -1480,15 +1482,11 @@ def build(self, model_path: str) -> onnx.ModelProto:
14801482
def build_value_info(self):
14811483
"""Build ValueInfo entries for weights and intermediate tensors."""
14821484
H = self.config.hidden_size
1483-
nh = self.config.num_attention_heads
14841485
nkv = self.config.num_key_value_heads
14851486
hd = self.head_dim
14861487
kv_hidden = nkv * hd
14871488
intermediate = self.config.intermediate_size
1488-
moe_intermediate = self.config.moe_intermediate_size
1489-
L = self.config.conv_L_cache
14901489
num_layers = self.config.num_hidden_layers
1491-
num_experts = self.config.num_experts
14921490
mask_prefix = "/model/attn_mask_reformat/attn_mask_subgraph"
14931491

14941492
# === Weight shapes (from initializers) ===
@@ -1509,7 +1507,9 @@ def build_value_info(self):
15091507

15101508
# === Embedding output ===
15111509
self.add_value_info(
1512-
"/model/embed_tokens/Gather/output_0", TensorProto.FLOAT, ["batch_size", "sequence_length", H]
1510+
"/model/embed_tokens/Gather/output_0",
1511+
TensorProto.FLOAT,
1512+
["batch_size", "sequence_length", H],
15131513
)
15141514

15151515
# === Per-layer outputs ===
@@ -1538,16 +1538,24 @@ def build_value_info(self):
15381538
["batch_size", 3 * H, "sequence_length"],
15391539
)
15401540
self.add_value_info(
1541-
f"{prefix}/conv/Split/output_0", TensorProto.FLOAT, ["batch_size", H, "sequence_length"]
1541+
f"{prefix}/conv/Split/output_0",
1542+
TensorProto.FLOAT,
1543+
["batch_size", H, "sequence_length"],
15421544
)
15431545
self.add_value_info(
1544-
f"{prefix}/conv/Split/output_1", TensorProto.FLOAT, ["batch_size", H, "sequence_length"]
1546+
f"{prefix}/conv/Split/output_1",
1547+
TensorProto.FLOAT,
1548+
["batch_size", H, "sequence_length"],
15451549
)
15461550
self.add_value_info(
1547-
f"{prefix}/conv/Split/output_2", TensorProto.FLOAT, ["batch_size", H, "sequence_length"]
1551+
f"{prefix}/conv/Split/output_2",
1552+
TensorProto.FLOAT,
1553+
["batch_size", H, "sequence_length"],
15481554
)
15491555
self.add_value_info(
1550-
f"{prefix}/conv/Mul_1/output_0", TensorProto.FLOAT, ["batch_size", H, "sequence_length"]
1556+
f"{prefix}/conv/Mul_1/output_0",
1557+
TensorProto.FLOAT,
1558+
["batch_size", H, "sequence_length"],
15511559
)
15521560
self.add_value_info(
15531561
f"{prefix}/conv/Conv_Input/output_0",
@@ -1557,9 +1565,13 @@ def build_value_info(self):
15571565
self.add_value_info(f"{prefix}/conv/Shape/output_0", TensorProto.INT64, [3])
15581566
self.add_value_info(f"{prefix}/conv/Gather_1/output_0", TensorProto.INT64, [])
15591567
self.add_value_info(f"{prefix}/conv/Neg_Seq_Len/output_0", TensorProto.INT64, [])
1560-
self.add_value_info(f"{prefix}/conv/Unsqueeze_starts/output_0", TensorProto.INT64, [1])
15611568
self.add_value_info(
1562-
f"{prefix}/conv/Mul_2/output_0", TensorProto.FLOAT, ["batch_size", H, "sequence_length"]
1569+
f"{prefix}/conv/Unsqueeze_starts/output_0", TensorProto.INT64, [1]
1570+
)
1571+
self.add_value_info(
1572+
f"{prefix}/conv/Mul_2/output_0",
1573+
TensorProto.FLOAT,
1574+
["batch_size", H, "sequence_length"],
15631575
)
15641576
self.add_value_info(
15651577
f"{prefix}/conv/Transpose_2/output_0",

src/liquidonnx/lfm2_vl/builder/vision_builder.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1179,9 +1179,7 @@ def build_encoder_layer(self, layer_idx: int, hidden_state: str) -> str:
11791179
)
11801180

11811181
# Community naming: Add_1 for attention residual
1182-
hidden_state = self.make_node(
1183-
"Add", [residual, out_proj], [f"{layer}/Add_1/output_0"]
1184-
)
1182+
hidden_state = self.make_node("Add", [residual, out_proj], [f"{layer}/Add_1/output_0"])
11851183

11861184
residual2 = hidden_state
11871185
normed2 = self.make_vision_layernorm(
@@ -1535,8 +1533,6 @@ def load_weights(self, weights: dict[str, np.ndarray]):
15351533
def build_value_info(self):
15361534
"""Build ValueInfo entries for weights and intermediate tensors."""
15371535
H = self.vision_hidden
1538-
nh = self.vision_config.num_attention_heads
1539-
hd = self.head_dim
15401536
intermediate = self.vision_config.intermediate_size
15411537
num_layers = self.vision_config.num_hidden_layers
15421538
text_hidden = self.text_hidden
@@ -1704,5 +1700,7 @@ def build(self) -> onnx.ModelProto:
17041700
self.build_value_info()
17051701

17061702
model = self.build_graph("embed_images")
1707-
logger.info(f"Vision + projector model built: {len(self.nodes)} nodes, {len(self.value_info)} value_info")
1703+
logger.info(
1704+
f"Vision + projector model built: {len(self.nodes)} nodes, {len(self.value_info)} value_info"
1705+
)
17081706
return model

tests/conftest.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,3 @@ def pytest_addoption(parser):
2525
def exports_dir(request) -> pathlib.Path:
2626
base = pathlib.Path(request.config.getoption("--exports-dir"))
2727
return base / "exports"
28-
29-

tests/test_lfm2/test_community_benchmark.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -189,8 +189,12 @@ def test_benchmark_comparison(
189189
pytest.skip(f"Community ONNX not available on HF for {model_id} {precision or 'fp32'}")
190190

191191
# Benchmark both
192-
local_result = benchmark_model(local_onnx_file, tokenizer, f"local-{model_name}-{precision or 'fp32'}")
193-
community_result = benchmark_model(community_onnx_file, tokenizer, f"community-{model_name}-{precision or 'fp32'}")
192+
local_result = benchmark_model(
193+
local_onnx_file, tokenizer, f"local-{model_name}-{precision or 'fp32'}"
194+
)
195+
community_result = benchmark_model(
196+
community_onnx_file, tokenizer, f"community-{model_name}-{precision or 'fp32'}"
197+
)
194198

195199
# Log results
196200
logger.info(f" Prefill: {PREFILL_TOKENS} tokens, Decode: {DECODE_TOKENS} tokens")

0 commit comments

Comments
 (0)