Skip to content

Commit dda9a70

Browse files
New tensor mehods - topk, divide, slice, and change implementations to use these methods
1 parent 506639f commit dda9a70

18 files changed

Lines changed: 249 additions & 76 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ playground/*
99
.idea
1010
.transformers-cache/*
1111
tests/models/*
12+
dist

composer.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,16 @@
1414
"type": "library",
1515
"require": {
1616
"php": "^8.1",
17-
"guzzlehttp/guzzle": "^7.0",
1817
"ankane/onnxruntime": "^0.2.0",
19-
"rindow/rindow-math-matrix": "^2.0",
18+
"guzzlehttp/guzzle": "^7.0",
2019
"codewithkyrian/jinja-php": "^1.0",
2120
"codewithkyrian/onnxruntime-downloader-plugin": "^1.1",
2221
"symfony/console": "^6.4|^7.0",
2322
"imagine/imagine": "^1.3",
2423
"rokka/imagine-vips": "^0.31.0",
25-
"rindow/rindow-math-matrix-matlibffi": "^1.0"
24+
"rindow/rindow-math-matrix": "^2.0",
25+
"rindow/rindow-matlib-ffi": "^1.0",
26+
"rindow/rindow-openblas-ffi": "^1.0"
2627
},
2728
"require-dev": {
2829
"pestphp/pest": "^2.31",

examples/pipelines/text-generation.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
ini_set('memory_limit', -1);
1313
//
1414
//$generator = pipeline('text-generation', 'Xenova/gpt2');
15-
$generator = pipeline('text-generation', 'Xenova/Qwen1.5-0.5B-Chat');
16-
//$generator = pipeline('text-generation', 'Xenova/TinyLlama-1.1B-Chat-v1.0');
15+
//$generator = pipeline('text-generation', 'Xenova/Qwen1.5-0.5B-Chat');
16+
$generator = pipeline('text-generation', 'Xenova/TinyLlama-1.1B-Chat-v1.0');
1717

1818
$streamer = StdOutStreamer::make();
1919

libs/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/*

libs/openblas.h renamed to libs/openblas-osx-arm64-0.3.27/include/openblas.h

File renamed without changes.

src/FeatureExtractors/ImageFeatureExtractor.php

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -453,7 +453,6 @@ public function preprocess(
453453

454454
$reshapedInputSize = [$image->height(), $image->width()];
455455

456-
457456
// All pixel-level manipulation occurs with data in the hwc format (height, width, channels),
458457
// to emulate the behavior of the original Python code (w/ numpy).
459458
$pixelData = $image->pixelData();
@@ -545,7 +544,6 @@ public function __invoke(Image|array $images, ...$args): array
545544
$originalSizes[] = $data['original_size'];
546545
$reshapedInputSizes[] = $data['reshaped_input_size'];
547546
}
548-
549547
return [
550548
'pixel_values' => $stackedPixelValues,
551549
'original_sizes' => $originalSizes,

src/Generation/Samplers/BeamSearchSampler.php

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,28 +18,27 @@ class BeamSearchSampler extends Sampler
1818
* @param int $index
1919
* @return array
2020
*/
21-
public function sample(Tensor $logits, int $index)
21+
public function sample(Tensor $logits, int $index): array
2222
{
23-
$shape = $logits->shape();
24-
$k = end($shape); // defaults to vocab size
23+
$vocabSize = $logits->shape()[$logits->ndim() - 1];
2524

26-
if ($this->generationConfig->top_k > 0) {
27-
$k = min($this->generationConfig->top_k, $k);
28-
}
25+
$k = $this->generationConfig->top_k > 0
26+
? min($this->generationConfig->top_k, $vocabSize)
27+
: $vocabSize; // defaults to vocab size
2928

3029
// Get logits of nth token
3130
$logs = $this->getLogits($logits, $index);
3231

3332
// Get top k tokens
34-
$topLogits = Math::getTopItems($logs, $k);
33+
[$topLogits, $topIndices] = $logs->topk($k);
3534

3635
// Compute softmax over logits
37-
$probabilities = Math::softmax(array_column($topLogits, 1));
36+
$probabilities = $topLogits->softmax()->toArray();
3837

3938
$sampledResults = [];
4039
for ($i = 0; $i < $this->generationConfig->num_beams; $i++) {
4140
$sampledResults[] = [
42-
$topLogits[$i][0], // token id
41+
$topIndices[$i], // token id
4342
log($probabilities[$i]), // score
4443
];
4544
}

src/Generation/Samplers/GreedySampler.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,11 @@ public function sample(Tensor $logits, int $index): array
2121
{
2222
// NOTE: no need to do log_softmax here since we only take the maximum
2323
$logs = $this->getLogits($logits, $index);
24-
$argmax = array_search(max($logs), $logs);
2524

2625
// Note: score is meaningless in this context, since we are performing
2726
// greedy search (p = 1 => log(p) = 0)
2827
return [
29-
[$argmax, 0]
28+
[$logs->argMax(), 0]
3029
];
3130
}
3231
}

src/Generation/Samplers/MultinomialSampler.php

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
use Codewithkyrian\Transformers\Utils\Math;
99
use Codewithkyrian\Transformers\Utils\Tensor;
10+
use function Codewithkyrian\Transformers\Utils\timeUsage;
1011

1112
class MultinomialSampler extends Sampler
1213
{
@@ -17,31 +18,30 @@ class MultinomialSampler extends Sampler
1718
* @param int $index
1819
* @return array
1920
*/
20-
public function sample(Tensor $logits, int $index)
21+
public function sample(Tensor $logits, int $index): array
2122
{
22-
$shape = $logits->shape();
23-
$k = end($shape); // defaults to vocab size
23+
$vocabSize = $logits->shape()[$logits->ndim() - 1];
2424

25-
if ($this->generationConfig->top_k > 0) {
26-
$k = min($this->generationConfig->top_k, $k);
27-
}
25+
$k = $this->generationConfig->top_k > 0
26+
? min($this->generationConfig->top_k, $vocabSize)
27+
: $vocabSize; // defaults to vocab size
2828

2929
// Get logits of nth token
3030
$logs = $this->getLogits($logits, $index);
3131

3232
// Get top k tokens
33-
$topLogits = Math::getTopItems($logs, $k);
33+
[$topLogits, $topIndices] = $logs->topk($k);
3434

3535
// Compute softmax over logits
36-
$probabilities = Math::softmax(array_column($topLogits, 1));
37-
36+
$probabilities = $topLogits->softmax()->toArray();
3837

3938
$sampledResults = [];
39+
4040
for ($i = 0; $i < $this->generationConfig->num_beams; $i++) {
4141
$sampledIndex = $this->randomSelect($probabilities);
4242

4343
$sampledResults[] = [
44-
$topLogits[$sampledIndex][0], // token id
44+
$topIndices[$sampledIndex], // token id
4545
log($probabilities[$sampledIndex]), // score
4646
];
4747
}

src/Generation/Samplers/Sampler.php

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,10 @@ abstract public function sample(Tensor $logits, int $index);
4444
* @param int $index
4545
* @return array
4646
*/
47-
public function getLogits(Tensor $logits, int $index): array
47+
public function getLogits(Tensor $logits, int $index): Tensor
4848
{
49-
$vocabSize = $logits->shape()[count($logits->shape()) - 1];
49+
$vocabSize = $logits->shape()[$logits->ndim() - 1];
50+
5051
// $logs = $logits->buffer()->toArray();
5152
//
5253
// if ($index === -1) {
@@ -56,21 +57,23 @@ public function getLogits(Tensor $logits, int $index): array
5657
// $logs = array_slice($logs, $startIndex, $startIndex + $vocabSize);
5758
// }
5859

59-
$start = $index === -1 ? $logits->buffer()->count() - $vocabSize : $index * $vocabSize;
60-
$end = $start + $vocabSize;
60+
$start = array_fill(0, $logits->ndim() - 2, 0);
61+
$size = array_fill(0, $logits->ndim() - 2, 1);
6162

62-
$logs = [];
63+
$start[] = $index;
64+
$size[] = 1;
6365

64-
for ($i = $start; $i < $end; $i++) {
65-
$logs[] = $logits->buffer()[$i];
66-
}
66+
$start[] = -$vocabSize;
67+
$size[] = $vocabSize;
68+
69+
$logs = $logits->newSlice($start, $size);
6770

68-
// add temperature
6971
if ($this->generationConfig->temperature > 0) {
70-
$logs = array_map(fn($x) => $x / $this->generationConfig->temperature, $logs);
72+
$logs = $logs->divide($this->generationConfig->temperature);
7173
}
7274

73-
return $logs;
75+
// Remove all dimensions of 1, leaving a flat 1D array of vocab_size
76+
return $logs->squeeze();
7477
}
7578

7679
/**
@@ -85,6 +88,7 @@ public function randomSelect(array $probabilities): int
8588

8689
// Generate a random number between 0 and the sum of probabilities
8790
$r = mt_rand() / mt_getrandmax() * $sumProbabilities;
91+
8892
foreach ($probabilities as $i => $probability) {
8993
$r -= $probability;
9094

0 commit comments

Comments
 (0)