Seeking Advice on Managing Memory Usage in Streamlit App

Hello everyone,

I’ve been working on a Streamlit app called MarketScouter (https://market.streamlit.app) that performs comprehensive stock market analysis. It uses various machine learning models and algorithms to provide stock recommendations. You can see a demo of the app in action here: MarketScouter: AI Trading Tool that CHANGES EVERYTHING! - YouTube

Recently, I’ve been running into resource and memory limit issues with the app. This happened even when I was the only one using it. I’ve tried to mitigate this by deleting all variables after they’re no longer needed, and I added gc.collect() but I’m not sure if this is sufficient, especially if multiple users are using the app concurrently.

I’ve also tried using @st.cache_data for the model.train and model.predict functions, but this led to errors and didn’t seem to work for my app.

Maybe my code was wrong? Please give an example of how to change my code to use this.

# Define model with smaller hidden layer
model = MLPRegressor(hidden_layer_sizes=(16,), activation='relu', solver='adam',  alpha=0.001, early_stopping=True)

# Train model
history = model.fit(state, reward)
# Evaluate model on validation set
val_predictions = model.predict(val_state)

I’m seeking advice on how to better manage memory usage in my Streamlit app. Specifically, I’m interested in strategies for handling memory usage when multiple users are using the app concurrently. I’m also curious if there are other Streamlit features to manage memory.

Any advice or insights would be greatly appreciated. Thank you in advance for your help!

1 Like

Hi @LunarClub,

Thanks for posting!

We have a section dedicated to caching that you might find very useful.

In your case, consider caching your model using st.cache_resource rather than st.cache_data as such;

@st.cache_resource
def train_model(state, reward):
    model = MLPRegressor(hidden_layer_sizes=(16,), activation='relu', solver='adam',  alpha=0.001, early_stopping=True)
    history = model.fit(state, reward)
    return model, history

model, history = train_model(state, reward)
val_predictions = model.predict(val_state)

Thanks @tonykip for the help
I will try this on all my ml stuff and hope it fixes the problem, I’ll let you know how it goes.
Also why does this work because I’m not really running the same function over and over again, the stock ticker I am looking for is always changing yet it runs into memory issues. So not sure why I needed to cache?

I don’t think caching can help you save memory.

I thought it was weird too but that’s what the article said when I ran out of memory…
Common app problems: Resource limits (streamlit.io)

I’m running a lot of different ml stuff when you enter a stock symbol, is this app even feasible on streamlit?

The example given there is a function without parameters that always returns (maybe a copy of) the same thing. But you are probably calling train_model(state, reward) with different parameters each time.

"[R]unning a lot of different ml stuff " doesn’t really say much about how much memory you are using and how it could be optimized.

I’m using FBProphet, Supervised Learning , and FinBert Sentiment analysis when you search for a stock ticker. Try the app and see, or watch the video I linked. As well as a lot of different indicators with pandas-ta for the historical price data that is downloaded.

And yeah, the training has to be different every time you search a different stock ticker.

model = Prophet()
model.fit(df)
forecast_days = int(timeframe_forecast.get(timeframe, None))
future = model.make_future_dataframe(periods=forecast_days)  

supervised learning

# Define state and reward for training data
state = train_data['Return'].values.reshape(-1, 1)
reward = np.where(train_data['Return'] > 0, 1, -1)
# Normalize state
scaler = StandardScaler()
state = scaler.fit_transform(train_state)

# Transform validation and test data using the scaler fitted on the training data

val_state = scaler.transform(val_state)
    # Preprocess test data
test_state = test_data['Return'].values.reshape(-1, 1)
test_state = scaler.transform(test_state)

@st.cache_resource
def train_model(state, reward):
    model = MLPRegressor(hidden_layer_sizes=(16,), activation='relu', solver='adam',  alpha=0.001, early_stopping=True)
    history = model.fit(state, reward)
    return model, history

model, history = train_model(state, reward)
val_predictions = model.predict(val_state)

I guess this sentiment analysis thing can be cached:

# Load models once
def load_models():
    tokenizer = BertTokenizer.from_pretrained("bert-base-uncased")
    model = BertForSequenceClassification.from_pretrained('ProsusAI/finbert', config='tokenizer_config.json', num_labels=3)
    return tokenizer, model

tokenizer, model = load_models()

            # Batch encode the texts
            inputs = tokenizer(list(batch_texts), return_tensors='pt', padding=True, truncation=True, max_length=512)

            # Get the model's output
            outputs = model(**inputs)

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.