Skip to content

Commit e35b5dc

Browse files
mgoinrahul-tuli
authored andcommitted
Remove scipy by implementing log_softmax (#1561)
1 parent 993b345 commit e35b5dc

File tree

6 files changed

+39
-11
lines changed

6 files changed

+39
-11
lines changed

setup.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -167,8 +167,7 @@ def _parse_requirements_file(file_path):
167167
_haystack_integration_deps = _parse_requirements_file(_haystack_requirements_file_path)
168168
_clip_deps = [
169169
"open_clip_torch==2.20.0",
170-
"scipy<1.10,>=1.8",
171-
"transformers<4.35",
170+
"transformers<4.37",
172171
]
173172

174173

src/deepsparse/clip/zeroshot_pipeline.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020

2121
from deepsparse.clip import CLIPTextInput, CLIPVisualInput
2222
from deepsparse.legacy.pipeline import BasePipeline, Pipeline
23-
from scipy.special import softmax
23+
from deepsparse.utils import numpy_softmax
2424

2525

2626
__all__ = ["CLIPZeroShotInput", "CLIPZeroShotOutput", "CLIPZeroShotPipeline"]
@@ -103,7 +103,7 @@ def __call__(self, *args, **kwargs):
103103
text_output /= lingalg.norm(text_output, axis=-1, keepdims=True)
104104

105105
output_product = 100.0 * visual_output @ text_output.T
106-
text_probs = softmax(output_product, axis=-1)
106+
text_probs = numpy_softmax(output_product, axis=-1)
107107

108108
return self.output_schema(text_scores=np.vsplit(text_probs, len(text_probs)))
109109

src/deepsparse/server/openai_server.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,9 @@
4646
)
4747
from deepsparse.server.server import Server
4848
from deepsparse.tasks import SupportedTasks
49-
from deepsparse.utils import InferenceState
49+
from deepsparse.utils import InferenceState, numpy_softmax
5050
from fastapi import BackgroundTasks, FastAPI, Request
5151
from fastapi.responses import StreamingResponse
52-
from scipy.special import softmax
5352

5453

5554
_LOGGER = logging.getLogger(__name__)
@@ -493,7 +492,7 @@ def create_logprobs(
493492
tokens = pipeline.tokenizer.batch_decode(token_ids)
494493

495494
for i in range(len(tokens)):
496-
log_prob = float(numpy.log(max(softmax(scores[i]))))
495+
log_prob = float(numpy.log(max(numpy_softmax(scores[i]))))
497496
logprobs.tokens.append(tokens[i])
498497
logprobs.token_logprobs.append(log_prob)
499498

src/deepsparse/transformers/metrics.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@
2121
import numpy
2222

2323
from deepsparse.utils.data import numpy_log_softmax
24-
from scipy.special import log_softmax
2524
from sklearn.metrics import precision_recall_fscore_support
25+
from deepsparse.utils import numpy_log_softmax
2626

2727

2828
__all__ = [
@@ -214,7 +214,7 @@ def _cross_entropy(
214214
float: The computed cross-entropy loss.
215215
"""
216216

217-
logp = log_softmax(predictions, axis=-1)
217+
logp = numpy_log_softmax(predictions, axis=-1)
218218
neg_log_likelihoods = -1.0 * numpy.take_along_axis(
219219
logp, numpy.expand_dims(targets, axis=-1), axis=-1
220220
)

src/deepsparse/utils/data.py

+30
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,36 @@ def numpy_softmax(x: numpy.ndarray, axis: int = 0):
170170
return softmax_x
171171

172172

173+
def numpy_log_softmax(x: numpy.ndarray, axis: int = 0):
174+
"""
175+
Ref: https://github.com/scipy/scipy/blob/v1.12.0/scipy/special/_logsumexp.py
176+
177+
In principle: log_softmax(x) = log(softmax(x))
178+
but using a more accurate implementation.
179+
180+
:param x: array containing values to be softmaxed
181+
:param axis: axis across which to perform softmax
182+
:return: x with values across axis softmaxed
183+
"""
184+
x_max = numpy.max(x, axis=axis, keepdims=True)
185+
186+
if x_max.ndim > 0:
187+
x_max[~numpy.isfinite(x_max)] = 0
188+
elif not numpy.isfinite(x_max):
189+
x_max = 0
190+
191+
tmp = x - x_max
192+
exp_tmp = numpy.exp(tmp)
193+
194+
# suppress warnings about log of zero
195+
with numpy.errstate(divide="ignore"):
196+
s = numpy.sum(exp_tmp, axis=axis, keepdims=True)
197+
out = numpy.log(s)
198+
199+
out = tmp - out
200+
return out
201+
202+
173203
def split_engine_inputs(
174204
items: List[numpy.ndarray], batch_size: int
175205
) -> Tuple[List[List[numpy.ndarray]], int]:

tests/server/test_openai.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@
2424
ModelPermission,
2525
OpenAIServer,
2626
)
27+
from deepsparse.utils import numpy_softmax
2728
from fastapi.testclient import TestClient
28-
from scipy.special import softmax
2929

3030

3131
TEST_MODEL_ID = "hf:mgoin/TinyStories-1M-ds"
@@ -246,7 +246,7 @@ def test_logprobs(client, model_card):
246246

247247
for local_gen, server_gen in zip(output.generations, response.json()["choices"]):
248248
local_top1_logprobs = [
249-
numpy.log(max(softmax(logits))) for logits in local_gen.score
249+
numpy.log(max(numpy_softmax(logits))) for logits in local_gen.score
250250
]
251251
server_top1_logprobs = server_gen["logprobs"]["token_logprobs"]
252252
assert numpy.allclose(local_top1_logprobs, server_top1_logprobs)

0 commit comments

Comments
 (0)