sample.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. package sample
  2. import (
  3. "cmp"
  4. "errors"
  5. "math"
  6. "slices"
  7. "gonum.org/v1/gonum/floats"
  8. "gonum.org/v1/gonum/stat/sampleuv"
  9. )
  10. type Sampler interface {
  11. Sample([]float64) ([]float64, error)
  12. }
  13. type Temperature float64
  14. func (t Temperature) Sample(logits []float64) ([]float64, error) {
  15. if t < 0 || t > 2 {
  16. return nil, errors.New("temperature must be between 0 and 2")
  17. }
  18. // subtracting max logit to avoid under/overflow
  19. maxLogit := floats.Max(logits)
  20. temp := math.Max(float64(t), 1e-7)
  21. for i := range logits {
  22. logits[i] = (logits[i] - maxLogit) / temp
  23. }
  24. return logits, nil
  25. }
  26. type softmax struct{}
  27. func Softmax() Sampler {
  28. return softmax{}
  29. }
  30. func (softmax) Sample(logits []float64) ([]float64, error) {
  31. return computeSoftmax(logits)
  32. }
  33. func computeSoftmax(logits []float64) ([]float64, error) {
  34. copiedLogits := make([]float64, len(logits))
  35. copy(copiedLogits, logits)
  36. for i := range copiedLogits {
  37. copiedLogits[i] = math.Exp(copiedLogits[i])
  38. }
  39. floatSum := floats.Sum(copiedLogits)
  40. floats.Scale(1.0/floatSum, copiedLogits)
  41. return copiedLogits, nil
  42. }
  43. type TopK int
  44. func (k TopK) Sample(logits []float64) ([]float64, error) {
  45. if k <= 0 {
  46. return nil, errors.New("k must be positive")
  47. }
  48. if int(k) >= len(logits) {
  49. return logits, nil
  50. }
  51. indices := make([]int, len(logits))
  52. for i := range indices {
  53. indices[i] = i
  54. }
  55. // sort in descending order
  56. slices.SortFunc(indices, func(i, j int) int {
  57. return cmp.Compare(logits[j], logits[i])
  58. })
  59. for _, idx := range indices[k:] {
  60. logits[idx] = math.NaN()
  61. }
  62. return logits, nil
  63. }
  64. type TopP float32
  65. func (p TopP) Sample(logits []float64) ([]float64, error) {
  66. if p <= 0 || p >= 1 {
  67. return nil, errors.New("p must be between 0 and 1")
  68. }
  69. probs, err := computeSoftmax(logits)
  70. if err != nil {
  71. return nil, err
  72. }
  73. indices := make([]int, len(probs))
  74. for i := range indices {
  75. indices[i] = i
  76. }
  77. // sort in descending order
  78. slices.SortFunc(indices, func(i, j int) int {
  79. return cmp.Compare(probs[j], probs[i])
  80. })
  81. cumSum := 0.0
  82. for i, idx := range indices {
  83. cumSum += probs[idx]
  84. if cumSum > float64(p) {
  85. for _, idx := range indices[i+1:] {
  86. logits[idx] = math.NaN()
  87. }
  88. break
  89. }
  90. }
  91. return logits, nil
  92. }
  93. type MinP float32
  94. func (p MinP) Sample(logits []float64) ([]float64, error) {
  95. if p <= 0 || p >= 1 {
  96. return nil, errors.New("p must be between 0 and 1")
  97. }
  98. probs, err := computeSoftmax(logits)
  99. if err != nil {
  100. return nil, err
  101. }
  102. copiedProbs := make([]float64, len(probs))
  103. copy(copiedProbs, probs)
  104. slices.Sort(copiedProbs)
  105. maxProb := copiedProbs[len(copiedProbs)-1]
  106. probThreshold := float64(p) * maxProb
  107. for i := range probs {
  108. if probs[i] < probThreshold {
  109. logits[i] = math.NaN()
  110. }
  111. }
  112. return logits, nil
  113. }
  114. type weighed struct{}
  115. func Weighed() Sampler {
  116. return weighed{}
  117. }
  118. func (s weighed) Sample(logits []float64) ([]float64, error) {
  119. logitsCopy := make([]float64, 0, len(logits))
  120. indices := make([]int, 0, len(logits))
  121. // the uv sampler does not support NaN values
  122. for i, logit := range logits {
  123. if !math.IsNaN(logit) {
  124. logitsCopy = append(logitsCopy, logit)
  125. indices = append(indices, i)
  126. }
  127. }
  128. if len(logitsCopy) == 0 {
  129. return nil, errors.New("no valid tokens found")
  130. }
  131. softmax, err := computeSoftmax(logitsCopy)
  132. if err != nil {
  133. return nil, err
  134. }
  135. w := sampleuv.NewWeighted(softmax, nil)
  136. if v, ok := w.Take(); ok {
  137. // returns the token ID
  138. return []float64{float64(indices[v])}, nil
  139. }
  140. return nil, errors.New("weighed sampler failed")
  141. }
  142. func Sample(logits []float64, samplers ...Sampler) ([]float64, error) {
  143. var err error
  144. for _, sampler := range samplers {
  145. if sampler == Temperature(0) {
  146. // early return with greedy if temperature is 0
  147. logits, err = Greedy().Sample(logits)
  148. if err != nil {
  149. return nil, err
  150. }
  151. return logits, nil
  152. }
  153. logits, err = sampler.Sample(logits)
  154. if err != nil {
  155. return nil, err
  156. }
  157. }
  158. return logits, nil
  159. }