FlanChanXwO commited on
Commit
5e14b6c
·
verified ·
1 Parent(s): d018672

Upload docs/zh/INFERENCE.md with huggingface_hub

Browse files
Files changed (1) hide show
  1. docs/zh/INFERENCE.md +120 -0
docs/zh/INFERENCE.md ADDED
@@ -0,0 +1,120 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 推理指南
2
+
3
+ ## 规格速览
4
+
5
+ | 项 | 值 |
6
+ |---|---|
7
+ | 输入名 | `input` |
8
+ | 输入形状 | `[batch, 3, 64, 160]` |
9
+ | 输入类型 | float32, 值域 [0,1] (RGB) |
10
+ | 输出名 | `logits` |
11
+ | 输出形状 | `[batch, 4, 10]` |
12
+ | 解码 | 每位置 argmax → 数字 |
13
+ | ONNX opset | 18 |
14
+
15
+ 预处理只有 3 步,无其他:RGB → 缩放到 160x64(双线性)→ 除以 255。
16
+ 不做灰度、不去噪、不做均值方差归一化。
17
+
18
+ ## Python
19
+
20
+ ```bash
21
+ pip install onnxruntime pillow numpy
22
+ ```
23
+
24
+ ```python
25
+ import numpy as np
26
+ import onnxruntime as ort
27
+ from PIL import Image
28
+
29
+ _SESSION = None
30
+
31
+ def get_session(model_path="model.onnx"):
32
+ global _SESSION
33
+ if _SESSION is None:
34
+ _SESSION = ort.InferenceSession(model_path, providers=["CPUExecutionProvider"])
35
+ return _SESSION
36
+
37
+ def solve_captcha(img_bytes_or_path, model_path="model.onnx"):
38
+ sess = get_session(model_path)
39
+ im = Image.open(img_bytes_or_path).convert("RGB").resize((160, 64), Image.BILINEAR)
40
+ x = np.asarray(im, dtype=np.float32) / 255.0
41
+ x = x.transpose(2, 0, 1)[None] # (1,3,64,160)
42
+ logits = sess.run(None, {"input": x})[0] # (1,4,10)
43
+ return "".join(str(int(logits[0, p].argmax())) for p in range(4))
44
+
45
+ code = solve_captcha("captcha.png") # "4821"
46
+ ```
47
+
48
+ ## Go (onnxruntime_go)
49
+
50
+ 依赖:`github.com/yalue/onnxruntime_go` + onnxruntime 共享库(.dylib/.so)。
51
+
52
+ ```go
53
+ package main
54
+
55
+ import (
56
+ "bytes"
57
+ "image"
58
+ _ "image/png"
59
+
60
+ "golang.org/x/image/draw"
61
+ ort "github.com/yalue/onnxruntime_go"
62
+ )
63
+
64
+ const (
65
+ inW, inH = 160, 64
66
+ nDigits = 4
67
+ )
68
+
69
+ type Solver struct {
70
+ sess *ort.Session[float32]
71
+ in *ort.Tensor[float32]
72
+ out *ort.Tensor[float32]
73
+ }
74
+
75
+ func NewSolver(modelPath, libPath string) (*Solver, error) {
76
+ if libPath != "" { ort.SetSharedLibraryPath(libPath) }
77
+ if err := ort.InitializeEnvironment(); err != nil { return nil, err }
78
+ in, err := ort.NewEmptyTensor[float32](ort.NewShape(1, 3, inH, inW))
79
+ if err != nil { return nil, err }
80
+ out, err := ort.NewEmptyTensor[float32](ort.NewShape(1, nDigits, 10))
81
+ if err != nil { in.Destroy(); return nil, err }
82
+ sess, err := ort.NewSession[float32](modelPath,
83
+ []string{"input"}, []string{"logits"},
84
+ []*ort.Tensor[float32]{in}, []*ort.Tensor[float32]{out})
85
+ if err != nil { in.Destroy(); out.Destroy(); return nil, err }
86
+ return &Solver{sess, in, out}, nil
87
+ }
88
+
89
+ func (s *Solver) Solve(png []byte) (string, error) {
90
+ src, _, err := image.Decode(bytes.NewReader(png))
91
+ if err != nil { return "", err }
92
+ dst := image.NewRGBA(image.Rect(0, 0, inW, inH))
93
+ draw.ApproxBiLinear.Scale(dst, dst.Bounds(), src, src.Bounds(), draw.Over, nil)
94
+
95
+ data := s.in.GetData()
96
+ idx := 0
97
+ // 模型输入为 NCHW:先写全部 R,再 G,再 B
98
+ for y := 0; y < inH; y++ { for x := 0; x < inW; x++ { r,_,_,_ := dst.At(x,y).RGBA(); data[idx]=float32(r>>8)/255; idx++ } }
99
+ for y := 0; y < inH; y++ { for x := 0; x < inW; x++ { _,g,_,_ := dst.At(x,y).RGBA(); data[idx]=float32(g>>8)/255; idx++ } }
100
+ for y := 0; y < inH; y++ { for x := 0; x < inW; x++ { _,_,b,_ := dst.At(x,y).RGBA(); data[idx]=float32(b>>8)/255; idx++ } }
101
+
102
+ if err := s.sess.Run(); err != nil { return "", err }
103
+ got := s.out.GetData()
104
+ code := make([]byte, nDigits)
105
+ for p := 0; p < nDigits; p++ {
106
+ best := 0
107
+ for c := 1; c < 10; c++ { if got[p*10+c] > got[p*10+best] { best = c } }
108
+ code[p] = '0' + byte(best)
109
+ }
110
+ return string(code), nil
111
+ }
112
+ ```
113
+
114
+ > 注意:`onnxruntime_go.NewSession` 从文件读模型。若用 `go:embed` 内嵌模型,改用 `NewSessionWithONNXData` 传字节。
115
+
116
+ ## 性能
117
+
118
+ - 单张推理:约 5-15ms(CPU,M1/现代 x86)
119
+ - 全流程(加载+预处理+推理):约 10-30ms
120
+ - 无 GPU 依赖,内存占用 < 50MB