or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

backend-integration.mdindex.mdmodel-composition.mdmodel-construction.mdmodel-hub.mdmodel-io.mdmodel-validation.mdnumpy-integration.mdoperator-definitions.mdreference-implementation.mdshape-inference.mdtext-processing.mdversion-conversion.md

text-processing.mddocs/

0

# Text Processing

1

2

Convert between ONNX protocol buffer representations and human-readable text formats for debugging, serialization, and model inspection. This module enables working with ONNX models in textual form for better readability and debugging.

3

4

## Capabilities

5

6

### Text Parsing

7

8

Parse human-readable text representations into ONNX protocol buffer objects.

9

10

```python { .api }

11

def parse_model(model_text):

12

"""

13

Parse text representation to ModelProto.

14

15

Parameters:

16

- model_text: String containing text representation of ONNX model

17

18

Returns:

19

ModelProto: Parsed model object

20

21

Raises:

22

ParseError: If text cannot be parsed or contains syntax errors

23

"""

24

25

def parse_graph(graph_text):

26

"""

27

Parse text representation to GraphProto.

28

29

Parameters:

30

- graph_text: String containing text representation of ONNX graph

31

32

Returns:

33

GraphProto: Parsed graph object

34

35

Raises:

36

ParseError: If text cannot be parsed or contains syntax errors

37

"""

38

39

def parse_function(function_text):

40

"""

41

Parse text representation to FunctionProto.

42

43

Parameters:

44

- function_text: String containing text representation of ONNX function

45

46

Returns:

47

FunctionProto: Parsed function object

48

49

Raises:

50

ParseError: If text cannot be parsed or contains syntax errors

51

"""

52

53

def parse_node(node_text):

54

"""

55

Parse text representation to NodeProto.

56

57

Parameters:

58

- node_text: String containing text representation of ONNX node

59

60

Returns:

61

NodeProto: Parsed node object

62

63

Raises:

64

ParseError: If text cannot be parsed or contains syntax errors

65

"""

66

```

67

68

### Text Generation

69

70

Convert ONNX protocol buffer objects to human-readable text representations.

71

72

```python { .api }

73

def to_text(proto):

74

"""

75

Convert ONNX proto to text representation.

76

77

Parameters:

78

- proto: ONNX protocol buffer object (ModelProto, GraphProto, FunctionProto, or NodeProto)

79

80

Returns:

81

str: Human-readable text representation

82

83

Raises:

84

ValueError: If proto type is not supported for text conversion

85

"""

86

```

87

88

### Exception Classes

89

90

Exception types for text processing errors.

91

92

```python { .api }

93

class ParseError(Exception):

94

"""

95

Exception raised when text parsing fails.

96

97

Contains detailed information about parsing errors including

98

line numbers and specific syntax issues.

99

"""

100

```

101

102

## Usage Examples

103

104

### Model Text Conversion

105

106

```python

107

import onnx

108

from onnx import printer, parser

109

110

# Load a binary model

111

model = onnx.load_model("example_model.onnx")

112

113

# Convert to text representation

114

model_text = printer.to_text(model)

115

print("Model in text format:")

116

print(model_text[:500] + "..." if len(model_text) > 500 else model_text)

117

118

# Save text representation to file

119

with open("model.txt", "w") as f:

120

f.write(model_text)

121

122

# Parse text back to model

123

try:

124

parsed_model = parser.parse_model(model_text)

125

126

# Verify they are equivalent

127

onnx.checker.check_model(parsed_model)

128

print("Text parsing and conversion successful!")

129

130

except parser.ParseError as e:

131

print(f"Parse error: {e}")

132

```

133

134

### Graph Inspection and Debugging

135

136

```python

137

import onnx

138

from onnx import printer, helper, TensorProto

139

import numpy as np

140

141

# Create a simple graph for demonstration

142

def create_debug_graph():

143

X = helper.make_tensor_value_info('input', TensorProto.FLOAT, [1, 3, 224, 224])

144

Y = helper.make_tensor_value_info('output', TensorProto.FLOAT, [1, 1000])

145

146

# Create some weights

147

conv_weight = np.random.randn(64, 3, 7, 7).astype(np.float32)

148

conv_tensor = helper.make_tensor('conv_weight', TensorProto.FLOAT,

149

conv_weight.shape, conv_weight)

150

151

fc_weight = np.random.randn(64, 1000).astype(np.float32)

152

fc_tensor = helper.make_tensor('fc_weight', TensorProto.FLOAT,

153

fc_weight.shape, fc_weight)

154

155

# Create nodes

156

conv_node = helper.make_node(

157

'Conv', ['input', 'conv_weight'], ['conv_out'],

158

kernel_shape=[7, 7], strides=[2, 2], pads=[3, 3, 3, 3]

159

)

160

161

relu_node = helper.make_node('Relu', ['conv_out'], ['relu_out'])

162

163

pool_node = helper.make_node('GlobalAveragePool', ['relu_out'], ['pool_out'])

164

165

reshape_node = helper.make_node('Flatten', ['pool_out'], ['flat_out'])

166

167

fc_node = helper.make_node('MatMul', ['flat_out', 'fc_weight'], ['output'])

168

169

# Create graph

170

graph = helper.make_graph(

171

[conv_node, relu_node, pool_node, reshape_node, fc_node],

172

'debug_model',

173

[X], [Y],

174

[conv_tensor, fc_tensor]

175

)

176

177

return helper.make_model(graph)

178

179

# Create and inspect model

180

debug_model = create_debug_graph()

181

182

# Print different components

183

print("=== FULL MODEL ===")

184

model_text = printer.to_text(debug_model)

185

print(model_text)

186

187

print("\n=== GRAPH ONLY ===")

188

graph_text = printer.to_text(debug_model.graph)

189

print(graph_text)

190

191

print("\n=== INDIVIDUAL NODES ===")

192

for i, node in enumerate(debug_model.graph.node):

193

node_text = printer.to_text(node)

194

print(f"Node {i} ({node.op_type}):")

195

print(node_text)

196

print()

197

```

198

199

### Interactive Model Editing

200

201

```python

202

import onnx

203

from onnx import printer, parser

204

205

def interactive_node_editor(model_path):

206

"""Interactive tool for editing model nodes via text."""

207

208

model = onnx.load_model(model_path)

209

210

print(f"Model has {len(model.graph.node)} nodes:")

211

for i, node in enumerate(model.graph.node):

212

print(f" {i}: {node.op_type} ({node.name or 'unnamed'})")

213

214

while True:

215

try:

216

node_idx = input("\nEnter node index to edit (or 'q' to quit): ")

217

if node_idx.lower() == 'q':

218

break

219

220

node_idx = int(node_idx)

221

if node_idx < 0 or node_idx >= len(model.graph.node):

222

print("Invalid node index")

223

continue

224

225

# Show current node

226

current_node = model.graph.node[node_idx]

227

node_text = printer.to_text(current_node)

228

print(f"\nCurrent node {node_idx}:")

229

print(node_text)

230

231

# Get new text

232

print("\nEnter new node definition (or press Enter to skip):")

233

new_text = input()

234

if not new_text.strip():

235

continue

236

237

# Parse new node

238

try:

239

new_node = parser.parse_node(new_text)

240

model.graph.node[node_idx].CopyFrom(new_node)

241

print("Node updated successfully!")

242

243

# Validate model

244

onnx.checker.check_model(model)

245

print("Model validation passed!")

246

247

except parser.ParseError as e:

248

print(f"Parse error: {e}")

249

except onnx.checker.ValidationError as e:

250

print(f"Validation error: {e}")

251

252

except (ValueError, KeyboardInterrupt):

253

print("Invalid input or interrupted")

254

continue

255

256

# Save modified model

257

save_path = input("\nEnter path to save modified model (or press Enter to skip): ")

258

if save_path.strip():

259

onnx.save_model(model, save_path)

260

print(f"Model saved to {save_path}")

261

262

# Example usage (commented out)

263

# interactive_node_editor("model.onnx")

264

```

265

266

### Model Comparison via Text

267

268

```python

269

import onnx

270

from onnx import printer

271

import difflib

272

273

def compare_models_text(model1_path, model2_path):

274

"""Compare two models using text diff."""

275

276

model1 = onnx.load_model(model1_path)

277

model2 = onnx.load_model(model2_path)

278

279

# Convert to text

280

text1 = printer.to_text(model1).splitlines()

281

text2 = printer.to_text(model2).splitlines()

282

283

# Generate diff

284

diff = list(difflib.unified_diff(

285

text1, text2,

286

fromfile=model1_path,

287

tofile=model2_path,

288

n=3

289

))

290

291

if diff:

292

print(f"Differences between {model1_path} and {model2_path}:")

293

for line in diff:

294

print(line)

295

else:

296

print("Models are identical in structure")

297

298

# Example usage (commented out)

299

# compare_models_text("model_v1.onnx", "model_v2.onnx")

300

```

301

302

### Text-Based Model Templates

303

304

```python

305

import onnx

306

from onnx import parser

307

308

def create_model_from_template():

309

"""Create models using text templates."""

310

311

# Define a model template

312

model_template = '''

313

ir_version: 7

314

producer_name: "text-template"

315

graph {

316

name: "linear_model"

317

input {

318

name: "input"

319

type {

320

tensor_type {

321

elem_type: 1

322

shape {

323

dim { dim_value: 1 }

324

dim { dim_value: 784 }

325

}

326

}

327

}

328

}

329

output {

330

name: "output"

331

type {

332

tensor_type {

333

elem_type: 1

334

shape {

335

dim { dim_value: 1 }

336

dim { dim_value: 10 }

337

}

338

}

339

}

340

}

341

initializer {

342

name: "weight"

343

data_type: 1

344

dims: 784

345

dims: 10

346

raw_data: "\\000\\000\\000..."

347

}

348

node {

349

input: "input"

350

input: "weight"

351

output: "output"

352

op_type: "MatMul"

353

}

354

}

355

opset_import {

356

version: 14

357

}

358

'''

359

360

try:

361

# Parse the template (this is a simplified example)

362

# In practice, you'd need proper tensor data

363

print("Model template:")

364

print(model_template)

365

366

# For a real implementation, you'd parse actual protobuf text format

367

print("Note: This is a demonstration of the text format structure")

368

print("Real implementation would require proper protobuf text parsing")

369

370

except Exception as e:

371

print(f"Template parsing error: {e}")

372

373

# Demonstrate text template structure

374

create_model_from_template()

375

```

376

377

### Text Format Validation

378

379

```python

380

import onnx

381

from onnx import parser, printer

382

383

def validate_text_roundtrip(model_path):

384

"""Validate that text conversion preserves model integrity."""

385

386

# Load original model

387

original_model = onnx.load_model(model_path)

388

print("Original model loaded successfully")

389

390

# Convert to text

391

model_text = printer.to_text(original_model)

392

print(f"Model converted to text ({len(model_text)} characters)")

393

394

try:

395

# Parse back from text

396

parsed_model = parser.parse_model(model_text)

397

print("Text parsed back to model successfully")

398

399

# Validate both models

400

onnx.checker.check_model(original_model)

401

onnx.checker.check_model(parsed_model)

402

print("Both models pass validation")

403

404

# Compare key properties

405

print("\nComparison:")

406

print(f" Nodes: {len(original_model.graph.node)} vs {len(parsed_model.graph.node)}")

407

print(f" Inputs: {len(original_model.graph.input)} vs {len(parsed_model.graph.input)}")

408

print(f" Outputs: {len(original_model.graph.output)} vs {len(parsed_model.graph.output)}")

409

print(f" Initializers: {len(original_model.graph.initializer)} vs {len(parsed_model.graph.initializer)}")

410

411

# Check if functionally equivalent

412

if (len(original_model.graph.node) == len(parsed_model.graph.node) and

413

len(original_model.graph.input) == len(parsed_model.graph.input) and

414

len(original_model.graph.output) == len(parsed_model.graph.output)):

415

print("✓ Text roundtrip preserves model structure")

416

else:

417

print("✗ Text roundtrip changed model structure")

418

419

except parser.ParseError as e:

420

print(f"✗ Parse error during roundtrip: {e}")

421

except onnx.checker.ValidationError as e:

422

print(f"✗ Validation error during roundtrip: {e}")

423

424

# Example usage (commented out)

425

# validate_text_roundtrip("model.onnx")

426

```