-
Here I'm trying to run this function.
I'm running my code in CPU in codespace with 32GB of RAM. This function kills the process because of out of memory. I tried to find a way to reduce memory consumption, especially emptying the cached memory after process of every iteration. I'm also considering another way, based on my experience in python that .eval() in pytorch helps reducing memory consumption. I have found that 'MustDrop()' in ts package drops the tensor, but I'm not sure that it will work. Am I in a right approach? |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 3 replies
-
@luxiant , We choose manual memory management in You can use Also, to stop autograd accumulation in inference mode, wrap model forward as you did is the way to go. Please see comment for potential leak below: // convert into input tensor and forward
var idTurnIntoTensor []ts.Tensor
idTurnIntoTensor = append(idTurnIntoTensor, *ts.TensorFrom(tokInput))
idInputTensor := ts.MustStack(idTurnIntoTensor, 0).MustTo(gotch.CPU, true)
// all original tensors must be deleted now as you just use the stacked tensor
for _, x := range idTurnIntoTensor{
x.MustDrop()
}
var torchResult *ts.Tensor
ts.NoGrad(func() {
// torchResult, _, _ = useModels.bertModel.ForwardT(idInputTensor, ts.None, ts.None, ts.None, ts.None, false)
torchResult, x, y := useModels.bertModel.ForwardT(idInputTensor, ts.None, ts.None, ts.None, ts.None, false)
// if x, y are tensors they must be explicitly deleted here
x.MustDrop()
y.MustDrop()
})
// clone the torchResult (for memory saving?) <- No. ShallowClone() just copy tensor.
torchResultCopy := torchResult.MustShallowClone() // <- `torchResult` may be a source of memory leak.
// get softmax value of each label
categoryProb := torchResultCopy.MustSoftmax(-1, gotch.Float, true)
var long, neutral, short float64
var sentiment string
probs := categoryProb.Float64Values() // <- categoryProb needs to free either with optional `categoryProb.Float64Values(true) or in a separate statement `categoryProb.MustDrop()`
categoryProb.MustDrop()
long = probs[0]
neutral = probs[1]
short = probs[2]
if long > neutral && long > short {
sentiment = "long"
} else if neutral > long && neutral > short {
sentiment = "neutral"
} else {
sentiment = "short"
} Hope that helps. |
Beta Was this translation helpful? Give feedback.
-
@luxiant , Nice memory profile graph! In general, I would create a simple inference example on CPU device and run for-loop input through it to check for any memory leak inside the model. Just have a quick look at your inference function and there a potential mem leak there: func (m *customModel) bertSentimentProcess(dataframe dataframe.DataFrame) sentimentRow {
var logit []float64
ts.NoGrad(func() {
torchResult, _, _ := m.bertModel.ForwardT(
// a new tensor is created by calling this function. Then no where you delete it.
processSentenceIntoInput(m.tokenizer, dataframe.Col("text").Records()[0]), // <-- this is the leak
ts.None,
ts.None,
ts.None,
ts.None,
false,
)
logit = torchResult.MustSoftmax(-1, gotch.Double, true).Float64Values(true)
})
var sentiment string
switch {
case logit[0] > logit[1] && logit[0] > logit[2]:
sentiment = "long"
case logit[1] > logit[0] && logit[1] > logit[2]:
sentiment = "neutral"
default:
sentiment = "short"
}
return sentimentRow{
post_num: dataframe.Col("post_num").Records()[0],
time: dataframe.Col("time").Records()[0],
text: dataframe.Col("text").Records()[0],
long: logit[0],
neutral: logit[1],
short: logit[2],
sentiment: sentiment,
}
} I would do in 2-step and delete the input after running forward: func (m *customModel) bertSentimentProcess(dataframe dataframe.DataFrame) sentimentRow {
var logit []float64
ts.NoGrad(func() {
// input is a newly created tensor
input := processSentenceIntoInput(m.tokenizer, dataframe.Col("text").Records()[0])
// Also, to avoid potential mem leak, I would receive all returned values if they have *ts.Tensor in them
// then delete if existing.
torchResult, unused1, unsed2:= m.bertModel.ForwardT(
input,
ts.None,
ts.None,
ts.None,
ts.None,
false,
)
input.MustDrop() // <-- delete after using.
// delete `unused1` and `unused2` here if they are not empty
logit = torchResult.MustSoftmax(-1, gotch.Double, true).Float64Values(true)
})
var sentiment string
switch {
case logit[0] > logit[1] && logit[0] > logit[2]:
sentiment = "long"
case logit[1] > logit[0] && logit[1] > logit[2]:
sentiment = "neutral"
default:
sentiment = "short"
}
return sentimentRow{
post_num: dataframe.Col("post_num").Records()[0],
time: dataframe.Col("time").Records()[0],
text: dataframe.Col("text").Records()[0],
long: logit[0],
neutral: logit[1],
short: logit[2],
sentiment: sentiment,
}
} |
Beta Was this translation helpful? Give feedback.
@luxiant ,
Nice memory profile graph! In general, I would create a simple inference example on CPU device and run for-loop input through it to check for any memory leak inside the model.
Just have a quick look at your inference function and there a potential mem leak there: