Generating Test-Cases for
ML Compilers
jiawei6@illinois.edu
University of Illinois, Urbana-Champaign
jiawei-site.github.io
Agenda
2
jiawei6@illinois.edu
University of Illinois, Urbana-Champaign
jiawei-site.github.io
DL system correctness is crucial
3
AI Applications
High-level AI Frameworks
Optimized Libraries
Hardware
AI Compilers & Optimizers
OpenAI Triton
NVIDIA GPUs
Google TPUs
CPUs
AMD GPUs
Apple Silicon
Safety
Functionality
User experience
jiawei6@illinois.edu
University of Illinois, Urbana-Champaign
jiawei-site.github.io
DL systems drive DNNs
A DL model (DNN) = a program
4
def classify(img: Tensor):
y = resize(img, dsize)
z = conv2d(y, ksize)
...
DL Model = Program
Data (Image)
“Bear”
DL system
jiawei6@illinois.edu
University of Illinois, Urbana-Champaign
jiawei-site.github.io
Test-case: DNN model + inputs
5
Test Generator
DL Computation
DL Compiler
Optimized
Non-opt.
Crash
Inconsistency
…
Oracle
How to Generate
Valid Models & Inputs?
jiawei6@illinois.edu
University of Illinois, Urbana-Champaign
jiawei-site.github.io
Generating valid models
Only valid models can be compiled and executed.
6
Parser
Graph passes
Low-level passes
Codegen
Runtime
Code path
Invalid models
Valid models
jiawei6@illinois.edu
University of Illinois, Urbana-Champaign
jiawei-site.github.io
Generating valid models
Model validity: each operator must be legally constructed
7
Invalid Model
x = ... # shape=[1,3,32,32]
y = avg_pool(x, ksize=33)
💥 Constraint Violation 💥
Kernel size (33) must be no larger (<=) than the last two dimensions (32)!
jiawei6@illinois.edu
University of Illinois, Urbana-Champaign
jiawei-site.github.io
NNSmith: Solver-aided Generation
8
x= input() # [x0,x1,x2]
y= relu(x) # [y0,y1,y2]
z= pool(y, ksize,stride)
[x0,x1,x2] =x.shape >0
[y0,y1,y2] =y.shape =x.shape
(y1-ksize)//stride > 0
(y2-ksize)//stride > 0
{x0=1, x1=8, x2=8, ksize=3,...}
Collect
Constraints
Solve Constraints
Concrete DNN
…
jiawei6@illinois.edu
University of Illinois, Urbana-Champaign
jiawei-site.github.io
Minimalist abstraction
9
Operator rule: a minimal set of properties for model validity
jiawei6@illinois.edu
University of Illinois, Urbana-Champaign
jiawei-site.github.io
Rule#1: Input constraints
A requires function that produces a set of predicates over input shape dims and attributes.
10
class Pool2d(OpBase):
# Declare attributes
def __init__(s, kh, kw, pad_h, ...):
s.kh = kh # height of kernel size
...
# Declare constraints� def requires(s, itensors: List[ATensor]):
ih, iw = itensors[0].shape[-2:]
return [
0 < s.kh < 2 * s.padh + ih,
0 < s.kw < 2 * s.padw + iw,
0 < s.stride, … ]
Example of Pool2D:
jiawei6@illinois.edu
University of Illinois, Urbana-Champaign
jiawei-site.github.io
Rule#2: Type (Shape) propagation
11
Input Layer
Layer 1
def requires(s, itensors):
...
output shape [c, h, w]
No problem!
[c, h, w] is known
jiawei6@illinois.edu
University of Illinois, Urbana-Champaign
jiawei-site.github.io
Rule#2: Type (Shape) propagation
12
Input Layer
Layer 1
Layer 2
def requires(s, itensors):
...
output shape [c, h, w]
output shape ???
Unknown…
Needs to deduce the shapes!
jiawei6@illinois.edu
University of Illinois, Urbana-Champaign
jiawei-site.github.io
Rule#2: Type (Shape) propagation
13
…
Prior layers.
class Pool2d(OpBase):
...
# Declare constraints� def requires(s, itensors: List[ATensor]):
...
# Declare propagation of shapes & dtypes
def type_transfer(s, itensors: List[ATensor])
→ List[ATensor]:
c, ih, iw = itensors[0].shape
oh = (ih + 2*s.padh - s.kh) // s.stride + 1
ow = (iw + 2*s.padw - s.kw) // s.stride + 1
return [ ATensor(
shape=(c, oh, ow),
dtype=itensors[0].dtype) ]
Pool2d
jiawei6@illinois.edu
University of Illinois, Urbana-Champaign
jiawei-site.github.io
Building a DNN = inserting next Op.
14
Input1
3x3 conv
Add
x,y,z > 0
c,h,w > 0
h-2 > 0
w-2 > 0
- - - - - -
x == c
y == h-2
z == w-2
[c,h,w]
[c,h-2,w-2]
Input0
[x,y,z]
x == c
y == h-2
z == w-2
def requires(s, itensors)
New Constraints
Global Constraints
✅SAT!
1. Randomly pick an operator type (Add)
2. Randomly pick its producers (Input & ReLU)
3. Collect and stack push new constraints
4. Constraint solving
jiawei6@illinois.edu
University of Illinois, Urbana-Champaign
jiawei-site.github.io
Building a DNN = inserting next Op.
15
Input1
3x3 conv
Add
[c,h,w]
[c,h-2,w-2]
Input0
[x,y,z]
def type_transfer(s, itensors)
[x,y,z]
1. Randomly pick an operator type (Add)
2. Randomly pick its producers (Input & ReLU)
3. Collect and stack push new constraints
4. Constraint solving
5. Goto #1
jiawei6@illinois.edu
University of Illinois, Urbana-Champaign
jiawei-site.github.io
Generating valid computational input
Model validity is NOT enough
16
T = {M, (X; W), O}
Test-case
✅ Model
❓ Computational Inputs
(Inputs & weights)
Expected Output
🚨 False Alarm 🚨
# Undefined behavior!
cast(NaN, to=int) => 🗑️
👻 False Negative 👻
# Normal input: 💥bug found
🐛BUGGY_ADD(1, 1) => 3
# NaN/Inf: 👻bug swallowed
🐛BUGGY_ADD(Inf, 1)=> Inf
jiawei6@illinois.edu
University of Illinois, Urbana-Champaign
jiawei-site.github.io
NNSmith: Input Search with Gradient
Goal: Search (X*; W*) s. t. M(X*; W*) doesn’t incur NaN/Inf
17
Gradient-guided Input Search:
Log(X)
jiawei6@illinois.edu
University of Illinois, Urbana-Champaign
jiawei-site.github.io
Evaluation Setup
18
Luo et al.
ICSE 21
LEMON
FSE 20
Tzer
OOPSLA 22
Systems under Test
Model-Level Fuzzer
TensorIR-Level Fuzzer
jiawei6@illinois.edu
University of Illinois, Urbana-Champaign
jiawei-site.github.io
NNSmith result highlights
19
Bug reports
[1] Luo et al. 2021. Graph-based Fuzz Testing for Deep Learning Inference Engines. (ICSE 2021)
jiawei6@illinois.edu
University of Illinois, Urbana-Champaign
jiawei-site.github.io
Diversifying Valid Models
20
Model Diversity
Operator Diversity
Manual and thus unscalable…
Can we automatically synthesize operator rules?
Automated Rule Inference
jiawei6@illinois.edu
University of Illinois, Urbana-Champaign
jiawei-site.github.io
NeuRI: Neural Net Rule Inference 🌠
21
Rule Synthesis
Test Suite
Model Hub
…
Filter
Simplify
Augment
Invocations
Trace Tensor APIs
Instrumentation
Simplified
Examples
Expr Prune
Rule Reuse
Deduplicate
Rule Inference
Shape
Propagation
Input
Constraints
Rules
Invocations
Forward
Backward
Hybrid DNN Generation
Concolic Op Insertion
GraphIR
Models
Interpreter
Compiler
Inconsistent
Results
Runtime
Error
Sanitizer
Error
Oracle Checking
Bug Reports
jiawei6@illinois.edu
University of Illinois, Urbana-Champaign
jiawei-site.github.io
Instrumenting Operator Invocation
22
avgpool( , ksize=2, …) =>
avgpool, [3,3,3], {ksize=2,…} => [3,2,2]
Simplify
API
Input Shapes
Attributes
Output Shapes
Invocation
Example
Record
Record
Example
avgpool, [3,3,3], {ksize=3, } => [3,1,1]
avgpool, [2,3,3], {ksize=2, } => [2,2,2]
avgpool, [3,3,4], {ksize=2,…} => [3,2,3]
Mutate & Validate
jiawei6@illinois.edu
University of Illinois, Urbana-Champaign
jiawei-site.github.io
Infer Operator Rules from Records
Each type (e.g., operator) of records has 3 sets of symbols
23
avgpool, [3,3,3], {ksize=3, } => [3,1,1]
avgpool, [2,3,3], {ksize=2, } => [2,2,2]
avgpool, [3,3,4], {ksize=2,…} => [3,2,3]
Input Shapes I
Attributes A
Output Shapes O
Question: How to infer f(A U I)?
jiawei6@illinois.edu
University of Illinois, Urbana-Champaign
jiawei-site.github.io
Inductive Rule Inference
Let f(A U I) be an expression under arithmetic grammar
24
⟨expr⟩ ::= ⟨op⟩ ⟨expr⟩⟨expr⟩ | ⟨item⟩
⟨item⟩ ::= ⟨symbol⟩ | ⟨literal⟩
⟨op⟩ ::= + | - | × | ÷ | min | max | mod
⟨symbol⟩ ::= Symbols from A U I
⟨literal⟩ ::= Constant integers
Search-based Inductive Synthesis: Enumerate all terms of the grammar s.t. ∃ expr satisfies all collected examples
jiawei6@illinois.edu
University of Illinois, Urbana-Champaign
jiawei-site.github.io
Optimizations
25
jiawei6@illinois.edu
University of Illinois, Urbana-Champaign
jiawei-site.github.io
Model Generation
26
Concrete
Operator Information
Symbolic
Operator Information
Records
Rule inferred
Rule not found
Works for me
Can we also make use of this?
jiawei6@illinois.edu
University of Illinois, Urbana-Champaign
jiawei-site.github.io
Concolic Model Generation
Using both concrete + symbolic (concolic) information
27
x= input() # [3,16,16]
y= pool(x,...) # [3,14,14]
Concrete
Operator Information
Query invocation w/
input shape [3,14,14]
reshape(y,[588])
x= input() # [3,16,16]
y= pool(x,...) # [3,14,14]
z= reshape(y,[588]) # inserted
jiawei6@illinois.edu
University of Illinois, Urbana-Champaign
jiawei-site.github.io
Evaluation Setup
28
NNSmith
ASPLOS 23
Muffin
ICSE 22
DeepREL
FSE 22
Variants of NeuRI
Systems under Test
Model-Level Fuzzer
Op-Level Fuzzer
jiawei6@illinois.edu
University of Illinois, Urbana-Champaign
jiawei-site.github.io
4-month bug finding with NeuRI
🔥 100 new bugs with 57 bugs fixed
🔥 9 bugs are marked as PyTorch
🔥 1 security vulnerability
29
Bug reports
“… the bugs you've reported are high quality … don't look like specially fuzzed set that's impossible to see in practice. They did reveal a few common themes that are easy to encounter in practice …”
-- PyTorch Developer (#93357)
jiawei6@illinois.edu
University of Illinois, Urbana-Champaign
jiawei-site.github.io
👩💻 pip install nnsmith
30
NNSmith Tutorial
Bug Reports
jiawei6@illinois.edu
University of Illinois, Urbana-Champaign
jiawei-site.github.io
👩💻Generate a PyTorch model
nnsmith.model_gen model.type=torch debug.viz=true
31
Add more options:
# A larger model
mgen.max_nodes=16
# Single input & single output
mgen.method="single-io-cinit"
jiawei6@illinois.edu
University of Illinois, Urbana-Champaign
jiawei-site.github.io
👩💻 Fuzzing PyTorch 2.0 compiler
nnsmith.fuzz fuzz.time=1m model.type=torch \
backend.type=pt2
32
jiawei6@illinois.edu
University of Illinois, Urbana-Champaign
jiawei-site.github.io
👩💻 Automating bug reports
When finding a bug, NNSmith turns it into a bug report.
33
jiawei6@illinois.edu
University of Illinois, Urbana-Champaign
jiawei-site.github.io
Thank you!
34
Homepage: https://jiawei-site.github.io/ or jw-liu.xyz/
Contact: jiawei6@illinois.edu @JiaweiLiu_
jiawei6@illinois.edu
University of Illinois, Urbana-Champaign
jiawei-site.github.io