fix: avoid GetOutputShape CGO crash by using fixed output dimensions
This commit is contained in:
@@ -311,13 +311,16 @@ func (h *Handler) Math(imageBase64 string) (result string, err error) {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// 获取输出形状
|
||||
outputShape, err := sess.GetOutputShape(0)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("获取输出形状失败: %v", err)
|
||||
// 不调用 GetOutputShape,直接从 output 大小推断
|
||||
// Math 模型输出固定为 [51, 1, 19] = 969 个元素 或 [19, 1, 51] = 969 个元素
|
||||
outputLen := len(output)
|
||||
if outputLen == 0 {
|
||||
return "", fmt.Errorf("模型输出为空")
|
||||
}
|
||||
|
||||
expr := decodeMath(output, outputShape)
|
||||
// 推断输出形状:已知 numChars=51, batch=1, timesteps=19, total=969
|
||||
// 尝试两种格式
|
||||
expr := decodeMathFromOutput(output)
|
||||
if expr == "" {
|
||||
return "", fmt.Errorf("无法识别表达式")
|
||||
}
|
||||
@@ -388,6 +391,95 @@ func preprocessMath(img image.Image) ([]float32, error) {
|
||||
return pixels, nil
|
||||
}
|
||||
|
||||
func decodeMathFromOutput(output []float32) string {
|
||||
// Math 模型输出固定: numChars=51, batch=1, timesteps=19, total=969
|
||||
// 可能的格式: [51, 1, 19] 或 [19, 1, 51]
|
||||
numChars := 51
|
||||
batch := 1
|
||||
timesteps := 19
|
||||
totalElems := numChars * batch * timesteps // 969
|
||||
|
||||
if len(output) != totalElems {
|
||||
// 尝试推断 timesteps
|
||||
timesteps = len(output) / numChars
|
||||
if timesteps <= 0 {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
// 尝试两种格式
|
||||
// 格式1: [T, B, C] = [19, 1, 51]
|
||||
result1 := decodeMathFormat(output, timesteps, batch, numChars, true)
|
||||
// 格式2: [C, B, T] = [51, 1, 19]
|
||||
result2 := decodeMathFormat(output, timesteps, batch, numChars, false)
|
||||
|
||||
// 返回更长的结果(更可能是正确的)
|
||||
if len(result1) >= len(result2) {
|
||||
return result1
|
||||
}
|
||||
return result2
|
||||
}
|
||||
|
||||
func decodeMathFormat(output []float32, timesteps, batch, numChars int, isTBC bool) string {
|
||||
var data []float32
|
||||
|
||||
if isTBC {
|
||||
// 格式: [T, B, C] -> [B, T, C]
|
||||
data = make([]float32, batch*timesteps*numChars)
|
||||
for t := 0; t < timesteps; t++ {
|
||||
for b := 0; b < batch; b++ {
|
||||
for c := 0; c < numChars; c++ {
|
||||
srcIdx := t*batch*numChars + b*numChars + c
|
||||
dstIdx := b*timesteps*numChars + t*numChars + c
|
||||
if srcIdx < len(output) && dstIdx < len(data) {
|
||||
data[dstIdx] = output[srcIdx]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 格式: [C, B, T] -> [B, T, C]
|
||||
data = make([]float32, batch*timesteps*numChars)
|
||||
for c := 0; c < numChars; c++ {
|
||||
for b := 0; b < batch; b++ {
|
||||
for t := 0; t < timesteps; t++ {
|
||||
srcIdx := c*batch*timesteps + b*timesteps + t
|
||||
dstIdx := b*timesteps*numChars + t*numChars + c
|
||||
if srcIdx < len(output) && dstIdx < len(data) {
|
||||
data[dstIdx] = output[srcIdx]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CTC 解码
|
||||
result := ""
|
||||
lastIdx := -1
|
||||
|
||||
for t := 0; t < timesteps; t++ {
|
||||
maxIdx := 0
|
||||
maxProb := float32(-math.MaxFloat32)
|
||||
|
||||
for c := 0; c < numChars; c++ {
|
||||
idx := t*numChars + c
|
||||
if idx < len(data) && data[idx] > maxProb {
|
||||
maxProb = data[idx]
|
||||
maxIdx = c
|
||||
}
|
||||
}
|
||||
|
||||
if maxIdx != 0 && maxIdx != lastIdx {
|
||||
if maxIdx-1 < len(mathChars) {
|
||||
result += string(mathChars[maxIdx-1])
|
||||
}
|
||||
}
|
||||
lastIdx = maxIdx
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func decodeMath(output []float32, outputShape []int64) string {
|
||||
// 原版逻辑:
|
||||
// if preds.shape[1] == 1: # Batch size is 1 at dim 1 implies [T, B, C]
|
||||
|
||||
Reference in New Issue
Block a user