fast_json.go 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. package sample
  2. import (
  3. "errors"
  4. "fmt"
  5. "math"
  6. "github.com/ollama/ollama/model"
  7. )
  8. type JSONState int
  9. const (
  10. StateStart JSONState = iota
  11. StateInObject
  12. StateInObjectKey
  13. StateNewline
  14. StateTab
  15. StateSpace
  16. StateInString
  17. StateInInt
  18. StateInFloat
  19. StateInBool
  20. StateInNull
  21. StateInColon
  22. StateInComma
  23. StateInTab
  24. StateInSpace
  25. StateInObjSpace
  26. StateInList
  27. StateInListComma
  28. StateListEnd
  29. StateInValue
  30. StateInValueEnd
  31. StateInListEnd
  32. StateInListObjectEnd
  33. StateInNewline
  34. StateInNumber
  35. StateInNumberEnd
  36. StateInStringEnd
  37. StateInObjectKeyEnd
  38. StateTerminate
  39. StateInObjectEnd
  40. StateTransitioningToTerminate
  41. )
  42. var JSONStates = []JSONState{
  43. StateStart,
  44. StateInObject,
  45. StateInObjectKey,
  46. StateNewline,
  47. StateTab,
  48. StateSpace,
  49. StateInString,
  50. StateInInt,
  51. StateInFloat,
  52. StateInBool,
  53. StateInNull,
  54. StateInColon,
  55. StateInComma,
  56. StateInTab,
  57. StateInSpace,
  58. StateInObjSpace,
  59. StateInList,
  60. StateInListComma,
  61. StateListEnd,
  62. StateInValue,
  63. StateInValueEnd,
  64. StateInListEnd,
  65. StateInListObjectEnd,
  66. StateInNewline,
  67. StateInNumber,
  68. StateInNumberEnd,
  69. StateInStringEnd,
  70. StateInObjectKeyEnd,
  71. StateTerminate,
  72. StateInObjectEnd,
  73. StateTransitioningToTerminate,
  74. }
  75. func (s JSONState) String() string {
  76. switch s {
  77. case StateStart:
  78. return "StateStart"
  79. case StateInObject:
  80. return "StateInObject"
  81. case StateInObjectKey:
  82. return "StateInObjectKey"
  83. case StateNewline:
  84. return "StateNewline"
  85. case StateTab:
  86. return "StateTab"
  87. case StateSpace:
  88. return "StateSpace"
  89. case StateInString:
  90. return "StateInString"
  91. case StateInInt:
  92. return "StateInInt"
  93. case StateInFloat:
  94. return "StateInFloat"
  95. case StateInBool:
  96. return "StateInBool"
  97. case StateInNull:
  98. return "StateInNull"
  99. case StateInColon:
  100. return "StateInColon"
  101. case StateInComma:
  102. return "StateInComma"
  103. case StateInTab:
  104. return "StateInTab"
  105. case StateInSpace:
  106. return "StateInSpace"
  107. case StateInObjSpace:
  108. return "StateInObjSpace"
  109. case StateInList:
  110. return "StateInList"
  111. case StateInListObjectEnd:
  112. return "StateInListObjectEnd"
  113. case StateInListComma:
  114. return "StateInListComma"
  115. case StateListEnd:
  116. return "StateListEnd"
  117. case StateInListEnd:
  118. return "StateInListEnd"
  119. case StateInNewline:
  120. return "StateInNewline"
  121. case StateInNumber:
  122. return "StateInNumber"
  123. case StateInNumberEnd:
  124. return "StateInNumberEnd"
  125. case StateInStringEnd:
  126. return "StateInStringEnd"
  127. case StateInObjectKeyEnd:
  128. return "StateInObjectKeyEnd"
  129. case StateTerminate:
  130. return "StateTerminate"
  131. case StateInObjectEnd:
  132. return "StateInObjectEnd"
  133. default:
  134. return fmt.Sprintf("Unknown state: %d", s)
  135. }
  136. }
  137. type JSONSampler struct {
  138. curNode *Node
  139. proc model.TextProcessor
  140. stack []*Node
  141. bracketCounter int
  142. }
  143. func NewJSONSampler(proc model.TextProcessor) (*JSONSampler, error) {
  144. // fmt.Println("Creating new JSON sampler")
  145. startNode, err := buildStateMachine(proc)
  146. if err != nil {
  147. return nil, err
  148. }
  149. js := &JSONSampler{
  150. curNode: startNode,
  151. proc: proc,
  152. stack: []*Node{},
  153. bracketCounter: 0,
  154. }
  155. return js, nil
  156. }
  157. func isTokenSubset(subset, superset []int32) bool {
  158. freq1 := make(map[int32]int)
  159. freq2 := make(map[int32]int)
  160. for _, v := range subset {
  161. freq1[v]++
  162. }
  163. for _, v := range superset {
  164. freq2[v]++
  165. }
  166. isSubset := true
  167. for k, count1 := range freq1 {
  168. count2 := freq2[k]
  169. if count1 > count2 {
  170. isSubset = false
  171. break
  172. }
  173. }
  174. return isSubset
  175. }
  176. func (s *JSONSampler) UpdateState(tokenSlice []int32) error {
  177. // fmt.Printf("Updating state with token: %v\n", tokenSlice)
  178. // fmt.Printf("Current state: %s\n", s.curNode.State)
  179. // fmt.Println("tokenSlice", tokenSlice)
  180. // todo: account for strings here
  181. objectTokens, err := ComputeTokenVariants([]string{"{", " {", "{\n", " {\n"}, s.proc)
  182. if err != nil {
  183. return err
  184. }
  185. // only move to terminate state if stack is empty
  186. if s.curNode.State == StateInObjectEnd {
  187. fmt.Println("debug: node.State", s.curNode.State)
  188. if len(s.stack) > 0 {
  189. s.stack = s.stack[:len(s.stack)-1]
  190. fmt.Println("popped and cur state", s.curNode.State)
  191. return nil
  192. }
  193. return nil
  194. }
  195. for node, edge := range s.curNode.TransitionEdges {
  196. for _, validToken := range edge {
  197. if isTokenSubset(tokenSlice, validToken) {
  198. s.curNode = node
  199. for _, token := range objectTokens {
  200. if isTokenSubset(tokenSlice, token) {
  201. fmt.Println("Appending to stack", s.curNode.State)
  202. s.stack = append(s.stack, s.curNode)
  203. }
  204. }
  205. // fmt.Printf("Transitioned to state: %s\n", node.State)
  206. return nil
  207. }
  208. }
  209. }
  210. for node, edge := range s.curNode.TransitionEdges {
  211. for _, validToken := range edge {
  212. if len(validToken) == 1 && validToken[0] == -1 || validToken[0] == -2 {
  213. s.curNode = node
  214. // fmt.Printf("Accepting any token, staying in state: %s\n", node.State)
  215. return nil
  216. }
  217. }
  218. }
  219. fmt.Println("invalid token ", tokenSlice)
  220. dec, err := s.proc.Decode(tokenSlice)
  221. if err != nil {
  222. return err
  223. }
  224. fmt.Println("decoded token ", dec)
  225. return errors.New("invalid token")
  226. }
  227. func (s *JSONSampler) Sample(logits []float64) ([]float64, error) {
  228. fmt.Printf("Sampling in state: %s\n", s.curNode.State)
  229. var err error
  230. switch s.curNode.State {
  231. case StateTerminate:
  232. for i := range logits {
  233. if s.proc.Is(uint32(i), model.SpecialEOS) {
  234. logits[i] = 1.0
  235. } else {
  236. logits[i] = math.NaN()
  237. }
  238. }
  239. return logits, nil
  240. case StateInInt:
  241. validStates := []int32{}
  242. minus, err := s.proc.Encode("-")
  243. if err != nil {
  244. return nil, err
  245. }
  246. digits := make([][]int32, 10)
  247. for i := 0; i < 10; i++ {
  248. digits[i], err = s.proc.Encode(fmt.Sprintf("%d", i))
  249. if err != nil {
  250. return nil, err
  251. }
  252. }
  253. // Allow "-" and digits 0-9 at start
  254. for i := range logits {
  255. for _, d := range digits {
  256. if len(d) == 1 && int32(i) == d[0] {
  257. validStates = append(validStates, int32(i))
  258. }
  259. }
  260. if len(minus) == 1 && int32(i) == minus[0] {
  261. validStates = append(validStates, int32(i))
  262. }
  263. }
  264. return logits, nil
  265. case StateInString:
  266. penalizeNewlineVariants := []string{"\n", " \"\n"}
  267. penalizeNewlineToks, err := ComputeTokenVariants(penalizeNewlineVariants, s.proc)
  268. if err != nil {
  269. return nil, err
  270. }
  271. penalizeNewlineToks = append(penalizeNewlineToks, []int32{702})
  272. logits, err = s.maskSpecificLogits(logits, penalizeNewlineToks)
  273. if err != nil {
  274. return nil, err
  275. }
  276. validStates := getValidStates(s.curNode)
  277. logits, err = s.maskLogits(logits, validStates)
  278. if err != nil {
  279. return nil, err
  280. }
  281. return logits, nil
  282. default:
  283. validStates := getValidStates(s.curNode)
  284. logits, err = s.maskLogits(logits, validStates)
  285. if err != nil {
  286. return nil, err
  287. }
  288. return logits, nil
  289. }
  290. }
  291. func getValidStates(node *Node) []int32 {
  292. validStates := []int32{}
  293. for _, edge := range node.TransitionEdges {
  294. for _, token := range edge {
  295. validStates = append(validStates, token...)
  296. }
  297. }
  298. return validStates
  299. }
  300. func (s *JSONSampler) maskLogits(logits []float64, validStates []int32) ([]float64, error) {
  301. // fmt.Printf("Masking logits with valid states: %v\n", validStates)
  302. // todo: this can prob be more efficient
  303. for i := range logits {
  304. isValid := false
  305. for _, token := range validStates {
  306. if token == -1 {
  307. // fmt.Println("Found sentinel token, returning unmasked logits")
  308. return logits, nil
  309. }
  310. if i == int(token) {
  311. // fmt.Printf("Found valid token: %d\n", token)
  312. isValid = true
  313. break
  314. }
  315. }
  316. if !isValid {
  317. logits[i] = math.NaN()
  318. }
  319. }
  320. return logits, nil
  321. }
  322. func (s *JSONSampler) maskSpecificLogits(logits []float64, tokensToMask []token) ([]float64, error) {
  323. // fmt.Printf("Masking specific logits: %v\n", tokensToMask)
  324. for i := range logits {
  325. for _, token := range tokensToMask {
  326. for _, chunked := range token {
  327. if int(chunked) == i {
  328. logits[i] = math.NaN()
  329. }
  330. }
  331. }
  332. }
  333. return logits, nil
  334. }