sample.go 4.2 KB

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