transforms.go 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. package sample
  2. import (
  3. "cmp"
  4. "math"
  5. "slices"
  6. pq "github.com/emirpasic/gods/v2/queues/priorityqueue"
  7. )
  8. type Transform interface {
  9. Apply([]float64) []float64
  10. }
  11. // TODO(parthsareen): potentially cache softmax values
  12. func softmax(logits []float64) []float64 {
  13. var sum float64
  14. probs := make([]float64, len(logits))
  15. for i, v := range logits {
  16. probs[i] = math.Exp(v)
  17. sum += probs[i]
  18. }
  19. for i := range probs {
  20. probs[i] /= sum
  21. }
  22. return probs
  23. }
  24. type Temperature float64
  25. func (t Temperature) Apply(logits []float64) []float64 {
  26. temp := math.Max(float64(t), 1e-7)
  27. // subtracting max logit to avoid under/overflow
  28. maxLogit := slices.Max(logits)
  29. for i := range logits {
  30. logits[i] = (logits[i] - maxLogit) / temp
  31. }
  32. return logits
  33. }
  34. type logitMap struct {
  35. index int
  36. logit float64
  37. }
  38. type TopK int
  39. // TODO(parthsareen): avoid having to check all logits after this transform
  40. func (k TopK) Apply(logits []float64) []float64 {
  41. if int(k) >= len(logits) {
  42. return logits
  43. }
  44. q := pq.NewWith(func(a, b logitMap) int {
  45. return -cmp.Compare(a.logit, b.logit)
  46. })
  47. for i, logit := range logits {
  48. q.Enqueue(logitMap{index: i, logit: logit})
  49. }
  50. validLogits := make(map[int]float64)
  51. for range k {
  52. logitMap, _ := q.Dequeue()
  53. validLogits[logitMap.index] = logitMap.logit
  54. }
  55. for i := range logits {
  56. if _, ok := validLogits[i]; !ok {
  57. logits[i] = math.Inf(-1)
  58. }
  59. }
  60. return logits
  61. }
  62. type TopP float64
  63. func (p TopP) Apply(logits []float64) []float64 {
  64. probs := softmax(logits)
  65. indices := make([]int, len(probs))
  66. for i := range indices {
  67. indices[i] = i
  68. }
  69. // sort in descending order
  70. slices.SortFunc(indices, func(i, j int) int {
  71. return cmp.Compare(probs[j], probs[i])
  72. })
  73. var sum float64
  74. for i, idx := range indices {
  75. sum += probs[idx]
  76. if sum > float64(p) {
  77. for _, idx := range indices[i+1:] {
  78. logits[idx] = math.Inf(-1)
  79. }
  80. break
  81. }
  82. }
  83. return logits
  84. }
  85. type MinP float64
  86. func (p MinP) Apply(logits []float64) []float64 {
  87. probs := softmax(logits)
  88. threshold := slices.Max(probs) * float64(p)
  89. for i, prob := range probs {
  90. if prob < threshold {
  91. logits[i] = math.Inf(-1)
  92. }
  93. }
  94. return logits
  95. }