> ## Documentation Index
> Fetch the complete documentation index at: https://developer.upsun.com/llms.txt
> Use this file to discover all available pages before exploring further.

# How to run PyTorch in an Upsun application?

> Learn how to deploy a sentiment analysis application powered by PyTorch and FastAPI on the Upsun cloud platform


export const PostMeta = ({data = {}}) => {
  const {author, date, image} = data;
  const authors = Array.isArray(author) ? author : author ? [author] : [];
  const resolveAuthor = slug => {
    const entry = AUTHOR_MAP[slug] || ({});
    const name = entry.name || slug;
    const github = entry.github || null;
    const linkedin = entry.linkedin || null;
    const url = github ? `https://github.com/${github}` : linkedin || null;
    const avatarUrl = github ? `https://github.com/${github}.png?size=64` : null;
    return {
      name,
      url,
      avatarUrl
    };
  };
  const formattedDate = date ? new Date(date).toLocaleDateString('en-US', {
    year: 'numeric',
    month: 'long',
    day: 'numeric'
  }) : null;
  if (!image && authors.length === 0 && !formattedDate) return null;
  const AUTHOR_MAP = {
    "aaron-collier": {
      "name": "Aaron Collier"
    },
    "aaron-dudenhofer": {
      "name": "Aaron Dudenhofer"
    },
    "aaron-porter": {
      "name": "Aaron Porter"
    },
    "adriaan-odendaal": {
      "name": "Adriaan Odendaal"
    },
    "ajmal": {
      "name": "Ajmal Siddiqui"
    },
    "akalipetis": {
      "name": "Antonis Kalipetis"
    },
    "alexander-varwijk": {
      "name": "Alexander Varwijk"
    },
    "alicia-bevilacqua": {
      "name": "Alicia Bevilacqua"
    },
    "amelie-deguerry": {
      "name": "Amelie Deguerry"
    },
    "anacidre": {
      "name": "Ana Cidre",
      "linkedin": "https://www.linkedin.com/in/ana-cidre"
    },
    "andoni": {
      "name": "Andoni Auzmendi"
    },
    "andrei-taranu": {
      "name": "Andrei (Alex) Taranu",
      "linkedin": "https://www.linkedin.com/in/andrei-alex-taranu/"
    },
    "andrew-baxter": {
      "name": "Andrew Baxter"
    },
    "andrew-melck": {
      "name": "Andrew Melck"
    },
    "antoine-crochet-damais": {
      "name": "Antoine Crochet Damais"
    },
    "augustin-delaporte": {
      "name": "Augustin Delaporte",
      "linkedin": "https://www.linkedin.com/in/augustindelaporte/"
    },
    "branislav-bujisic": {
      "name": "Branislav Bujisic"
    },
    "carl-smith": {
      "name": "Carl Smith"
    },
    "caroline-leroy": {
      "name": "Caroline Leroy"
    },
    "cati-mayer": {
      "name": "Cati Mayer"
    },
    "catplat": {
      "name": "C Trinkwon"
    },
    "ceelolulu": {
      "name": "Celeste van der Watt"
    },
    "chadwcarlson": {
      "name": "Chad Carlson",
      "github": "chadwcarlson",
      "linkedin": "https://www.linkedin.com/in/chadwcarlson"
    },
    "chris-ward": {
      "name": "Chris Ward"
    },
    "chris-yates": {
      "name": "Chris Yates"
    },
    "christian-sieber": {
      "name": "Christian Sieber"
    },
    "christopher-lockheardt": {
      "name": "Christopher Lockheardt"
    },
    "christopher-skene": {
      "name": "Christopher Skene"
    },
    "chuck-morgan": {
      "name": "Chuck Morgan"
    },
    "corey-dockendorf": {
      "name": "Corey Dockendorf"
    },
    "crell": {
      "name": "Crell"
    },
    "damz": {
      "name": "Damz"
    },
    "dan-morrison": {
      "name": "Dan Morrison"
    },
    "davidbonachera": {
      "name": "David Bonachera",
      "github": "davidbonachera",
      "linkedin": "https://www.linkedin.com/in/davidbonachera"
    },
    "dereliahmet1": {
      "name": "Ahmet Faruk Dereli"
    },
    "devicezero": {
      "name": "Jonas Kröger",
      "github": "devicezero",
      "linkedin": "https://www.linkedin.com/in/jonaskroeger/"
    },
    "doug-goldberg": {
      "name": "Doug Goldberg"
    },
    "duncan-naves": {
      "name": "Duncan Naves",
      "github": "duncannaves",
      "linkedin": "https://www.linkedin.com/in/duncan-naves-a94423aa"
    },
    "erika-bustamante": {
      "name": "Erika Bustamante"
    },
    "fabpot": {
      "name": "Fabien Potencier"
    },
    "flovntp": {
      "name": "Florent Huck",
      "github": "flovntp",
      "linkedin": "https://www.linkedin.com/in/florenthuck"
    },
    "fred-plais": {
      "name": "Fred Plais"
    },
    "gauthier-garnier": {
      "name": "Gauthier Garnier"
    },
    "gilzow": {
      "name": "Paul Gilzow"
    },
    "gmoigneu": {
      "name": "Guillaume Moigneu",
      "github": "gmoigneu",
      "linkedin": "https://www.linkedin.com/in/guillaumemoigneu/"
    },
    "gregqualls": {
      "name": "Greg Qualls"
    },
    "guguss": {
      "name": "Augustin Delaporte"
    },
    "haylee-millar": {
      "name": "Haylee Millar"
    },
    "ivana-kotur": {
      "name": "Ivana Kotur"
    },
    "jackrabbithanna": {
      "name": "Mark Hanna"
    },
    "jared-wright": {
      "name": "Jared Wright",
      "github": "jww-sh",
      "linkedin": "https://www.linkedin.com/in/jaredwaynewright"
    },
    "jessica-orozco": {
      "name": "Jessica Orozco"
    },
    "joey-stanford": {
      "name": "Joey Stanford"
    },
    "john-grubb": {
      "name": "John Grubb"
    },
    "jonas-kruger": {
      "name": "Jonas Kruger"
    },
    "kathryn-frazer": {
      "name": "Kathryn Frazer"
    },
    "kemiojo": {
      "name": "Kemi Elizabeth Ojogbede"
    },
    "kieronsambrook-smith": {
      "name": "Kieronsambrook Smith"
    },
    "laurent-arnoud": {
      "name": "Laurent Arnoud"
    },
    "letoya-boyne": {
      "name": "Letoya Boyne"
    },
    "lolautruche": {
      "name": "Jérôme Vieilledent"
    },
    "lyly-lepinay": {
      "name": "Lyly Lepinay"
    },
    "manauwar-alam": {
      "name": "Manauwar Alam"
    },
    "marc-antoine-porri": {
      "name": "Marc Antoine Porri"
    },
    "maria-antinkaapo": {
      "name": "Maria Antinkaapo"
    },
    "maria-de-anton": {
      "name": "Maria De Anton"
    },
    "mark-dorison": {
      "name": "Mark Dorison"
    },
    "markus-hausammann": {
      "name": "Markus Hausammann"
    },
    "mary-thomas": {
      "name": "Mary Thomas"
    },
    "mathias-bolt-lesniak": {
      "name": "Mathias Bolt Lesniak"
    },
    "mathieu-strauch": {
      "name": "Mathieu Strauch"
    },
    "matthias-van-woensel": {
      "name": "Matthias Van Woensel",
      "linkedin": "https://www.linkedin.com/in/matthias-van-woensel-267a069"
    },
    "michael-sharp": {
      "name": "Michael Sharp"
    },
    "mupsi": {
      "name": "Marine Gandy"
    },
    "natalie-harper": {
      "name": "Natalie Harper"
    },
    "ngommenginger": {
      "name": "Nicolas Gommenginger",
      "linkedin": "https://www.linkedin.com/in/nicolas-gommenginger"
    },
    "nicholas-bennison": {
      "name": "Nicholas Bennison"
    },
    "nicholas-vahalik": {
      "name": "Nicholas Vahalik"
    },
    "nick-hardiman": {
      "name": "Nick Hardiman"
    },
    "nickanderegg": {
      "name": "Nickanderegg"
    },
    "nicolas-grekas": {
      "name": "Nicolas Grekas",
      "github": "nicolas-grekas",
      "linkedin": "https://www.linkedin.com/in/nicolasgrekas/"
    },
    "niti-malwade": {
      "name": "Niti Malwade"
    },
    "opensocialteam": {
      "name": "Opensocialteam"
    },
    "ori-pekelman": {
      "name": "Ori Pekelman"
    },
    "otavio-santana": {
      "name": "Otavio Santana"
    },
    "palwandi": {
      "name": "Pawan Alwandi",
      "github": "pawpy",
      "linkedin": "https://www.linkedin.com/in/pawanalwandi"
    },
    "patrick-boest": {
      "name": "Patrick Boest"
    },
    "patrick-dawkins": {
      "name": "Patrick Dawkins",
      "github": "pjcdawkins",
      "linkedin": "https://www.linkedin.com/in/patrickdawkins"
    },
    "patrick-klima": {
      "name": "Patrick Klima"
    },
    "pjcdawkins": {
      "name": "Pjcdawkins"
    },
    "prineet-kaurbhurji": {
      "name": "Prineet Kaurbhurji"
    },
    "quentin-sinig": {
      "name": "Quentin Sinig"
    },
    "ralt": {
      "name": "Florian Margaine",
      "github": "ralt",
      "linkedin": "https://www.linkedin.com/in/florian-margaine-43971136"
    },
    "ramanathanramakrishnamurthy": {
      "name": "Ramanathanramakrishnamurthy"
    },
    "remi-lejeune": {
      "name": "Rémi Lejeune"
    },
    "ribel": {
      "name": "Taras Kruts"
    },
    "robert-douglass": {
      "name": "Robert Douglass"
    },
    "rudy-weber": {
      "name": "Rudy Weber"
    },
    "ryan-hicks": {
      "name": "Ryan Hicks"
    },
    "sabri-helal": {
      "name": "Sabri Helal"
    },
    "savannah-bergeron": {
      "name": "Savannah Bergeron"
    },
    "shannon-vettes": {
      "name": "Shannon Vettes"
    },
    "shawn-ogasawara": {
      "name": "Shawn Ogasawara",
      "linkedin": "https://www.linkedin.com/in/shawn-ogasawara-83a9a0/"
    },
    "shawna-spoor": {
      "name": "Shawna Spoor"
    },
    "shedrack-akintayo": {
      "name": "Shedrack Akintayo"
    },
    "simon-ruggier": {
      "name": "Simon Ruggier"
    },
    "sophie-van-der-kindere": {
      "name": "Sophie Van Der Kindere"
    },
    "stefanos-thampis": {
      "name": "Stefanos Thampis"
    },
    "stephen-weinberg": {
      "name": "Stephen Weinberg"
    },
    "sukhman-virk": {
      "name": "Sukhman Virk"
    },
    "sumaira-nazir": {
      "name": "Sumaira Nazir"
    },
    "sumer": {
      "name": "Sümer Cip"
    },
    "syed-raza": {
      "name": "Syed Raza"
    },
    "tamara-bacchia": {
      "name": "Tamara Bacchia"
    },
    "tara-arnold": {
      "name": "Tara Arnold"
    },
    "theosakamg": {
      "name": "Mickael Gaillard",
      "github": "theosakamg"
    },
    "thomasdiluccio": {
      "name": "Thomas di Luccio"
    },
    "tim-anderson": {
      "name": "Tim Anderson"
    },
    "tom-helmer-hansen": {
      "name": "Tom Helmer Hansen"
    },
    "tylermills": {
      "name": "Tyler Mills"
    },
    "upsun": {
      "name": "Upsun"
    },
    "veronika-tolkachova": {
      "name": "Veronika Tolkachova",
      "linkedin": "https://www.linkedin.com/in/veronika-tolkachova-169167a2"
    },
    "vince-parker": {
      "name": "Vince Parker"
    },
    "vinnie-russo": {
      "name": "Vincenzo Russo"
    },
    "vrobert78": {
      "name": "Vincent Robert",
      "github": "vrobert78",
      "linkedin": "https://www.linkedin.com/in/vincent-robert-498a883"
    },
    "yuriy-babenko": {
      "name": "Yuriy Babenko"
    },
    "yuriy-gerasimov": {
      "name": "Yuriy Gerasimov"
    }
  };
  return <div className="post-meta">
      {(authors.length > 0 || formattedDate) && <div className="post-meta-info">
          {authors.length > 0 && <div className="post-meta-authors">
              {authors.map(slug => {
    const {name, url, avatarUrl} = resolveAuthor(slug);
    const inner = <>
                    {avatarUrl && <img src={avatarUrl} alt={name} className="post-meta-avatar" />}
                    <span className="post-meta-author-name">{name}</span>
                  </>;
    return url ? <a key={slug} href={url} target="_blank" rel="noopener noreferrer" className="post-meta-author">
                    {inner}
                  </a> : <span key={slug} className="post-meta-author">{inner}</span>;
  })}
            </div>}
          {authors.length > 0 && formattedDate && <span className="post-meta-separator" aria-hidden="true">·</span>}
          {formattedDate && <span className="post-meta-date">{formattedDate}</span>}
        </div>}
      {image && <img src={image} alt="" className="post-meta-image" aria-hidden="true" />}
    </div>;
};

<PostMeta data={{ author: ["gmoigneu"], date: "2025-05-01T14:00:00+00:00", image: "/images/posts/hands-on/pytorch-running-on-upsun/pytorch.webp" }} />

PyTorch is one of the most popular deep learning frameworks, particularly for natural language processing tasks. This tutorial will guide you through creating a sentiment analysis API using **PyTorch** and **FastAPI**, then deploying it on the **Upsun** Cloud Application Platform.

## Prerequisites

* An Upsun account
* Basic knowledge of Python
* Familiarity with REST APIs
* Git installed on your local machine

## Setting Up a new Python application on Upsun

Let's start by creating a new Python application on Upsun. We'll use **Python 3.12**, which is well-supported by both PyTorch and Upsun.

### 1. Create a new project directory

First, let's create a new directory for our project and initialize it as a Git repository:

```bash {filename="Terminal"} theme={null}
mkdir pytorch-sentiment-api
cd pytorch-sentiment-api
git init
```

### 2. Configure the Upsun project

Create the necessary Upsun configuration files to define our application's environment. First, create a `.upsun` directory and then a `config.yaml` file inside it:

```bash {filename="Terminal"} theme={null}
mkdir -p .upsun
touch .upsun/config.yaml
```

Now, open the `config.yaml` file and add the following configuration:

```yaml {filename=".upsun/config.yaml"} theme={null}
# Define the applications within the project
applications:
  # Name of the application (can be anything, 'api' used here)
  api:
    # Request a container with more memory, suitable for ML models
    container_profile: HIGH_MEMORY

    # Specify the language and version for the runtime environment
    type: "python:3.12"

    # Define persistent storage mounts for the application container
    mounts:
      # Mount a persistent storage volume named 'pycache' at /app/__pycache__
      # This persists compiled Python bytecode across deployments
      "__pycache__":
        source: "storage" # Use Upsun persistent storage
        source_path: "pycache" # Subdirectory within the storage volume
      # Mount a persistent storage volume named 'cache' at /app/.cache
      # Used by tools like pip or transformers to cache downloads
      ".cache":
        source: "storage"
        source_path: "cache"

    # Configuration for how the application serves web requests
    web:
      # The command Upsun runs to start the web server
      # Uses the PORT environment variable provided by Upsun
      commands:
        start: "uvicorn main:app --host 0.0.0.0 --port $PORT"
      # Defines how Upsun communicates with the application internally
      upstream:
        socket_family: tcp # Use TCP sockets
      # Defines how specific paths are handled
      locations:
        # For the root path "/"
        "/":
          root: ""
          passthru: true # Pass requests directly to the application (defined by commands.start)
          
    # Commands to run during different phases of the deployment process
    hooks:
      # Commands executed during the build phase
      build: |
        set -eux # Exit on error, print commands
        pip install --upgrade pip # Ensure pip is up-to-date
        pip install -r requirements.txt # Install dependencies
        # Compile Python files to bytecode for potentially faster startup
        python -m compileall .

# Define how incoming HTTP/HTTPS requests are routed to applications
routes:
  # Route requests for the default domain(s) configured for the environment
  "https://{default}/":
    type: upstream # Route to an application defined above
    upstream: "api:http" # Route to the 'api' application using HTTP
```

## Creating a FastAPI application for sentiment analysis

Now, let's create our FastAPI application that will serve as the API for our sentiment analysis model.

### 1. Set up the project structure

Let's organize our project with the following structure:

```
pytorch-sentiment-api/
├── .upsun/
│   └── config.yaml
├── main.py
├── model.py
├── requirements.txt
└── README.md
```

### 2. Define the requirements

Create a `requirements.txt` file with the necessary dependencies:

```txt {filename="requirements.txt"} theme={null}
fastapi>=0.68.0
uvicorn>=0.15.0
--extra-index-url https://download.pytorch.org/whl/cpu
torch==2.1.0+cpu
transformers>=4.11.0
pydantic>=1.8.0
```

Notice how we're using the `--extra-index-url` directive to specify that we want the CPU-only version of PyTorch, which is much smaller and suitable for deployment on CPU based containers.

### 3. Create the Model module

Let's create a `model.py` file that will handle the sentiment analysis logic:

```python {filename="model.py"} theme={null}
from transformers import pipeline
import torch

class SentimentModel:
    def __init__(self):
        # Verify we're using the CPU version
        print(f"CUDA available: {torch.cuda.is_available()}")
        print(f"PyTorch version: {torch.__version__}")
        
        # Load a small pretrained model for sentiment analysis
        self.classifier = pipeline(
            "sentiment-analysis",
            model="distilbert-base-uncased-finetuned-sst-2-english",
            return_all_scores=True
        )
    
    def predict(self, text):
        """
        Predict the sentiment of the given text.
        Returns the sentiment (POSITIVE/NEGATIVE) and confidence score.
        """
        result = self.classifier(text)
        
        # Process the results
        scores = result[0]
        
        # Find the label with the highest score
        highest_score = max(scores, key=lambda x: x['score'])
        sentiment = highest_score['label']
        confidence = highest_score['score']
        
        return {
            "text": text,
            "sentiment": sentiment,
            "confidence": confidence,
            "all_scores": scores
        }
```

### 4. Create the FastAPI application

Now, let's create the `main.py` file for our FastAPI application:

```python {filename="main.py"} theme={null}
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
import os
import time
from model import SentimentModel

# Create the FastAPI app
app = FastAPI(
    title="Sentiment Analysis API",
    description="An API for sentiment analysis using PyTorch and transformers",
    version="1.0.0"
)

# Load the model (this might take a moment)
print("Loading sentiment analysis model...")
model = None

# Define request and response models
class SentimentRequest(BaseModel):
    text: str

class SentimentResponse(BaseModel):
    text: str
    sentiment: str
    confidence: float

@app.on_event("startup")
async def startup_event():
    global model
    model = SentimentModel()
    print("Model loaded successfully!")

@app.get("/")
def read_root():
    return {"message": "Welcome to the Sentiment Analysis API"}

@app.post("/classification", response_model=SentimentResponse)
async def classify_sentiment(request: SentimentRequest):
    if not model:
        raise HTTPException(status_code=503, detail="Model not loaded yet")
    
    if not request.text or len(request.text.strip()) == 0:
        raise HTTPException(status_code=400, detail="Empty text provided")
    
    try:
        # Perform the prediction
        result = model.predict(request.text)
        
        # Return the response
        return {
            "text": request.text,
            "sentiment": result["sentiment"],
            "confidence": result["confidence"]
        }
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Error during prediction: {str(e)}")

@app.get("/health")
def health_check():
    return {"status": "healthy", "model_loaded": model is not None}
```

## Deploying the application to Upsun

Now that we have our application ready, let's deploy it to Upsun.

### 1. Initialize Git repository

Make sure all files are added to Git:

```bash {filename="Terminal"} theme={null}
git add .
git commit -m "Initial commit of PyTorch sentiment analysis API"
```

### 2. Create a new Upsun project

You can create a new Upsun project through the Upsun Console or using the Upsun CLI:

```bash {filename="Terminal"} theme={null}
upsun project:create # and follow the prompts!
```

The Upsun remote should be set automatically on the repository. If it's not, use

```bash {filename="Terminal"} theme={null}
upsun project:set {project_id}
```

### 3. Push to Upsun

Deploy your application by pushing your code to Upsun:

```bash {filename="Terminal"} theme={null}
upsun push -y
```

Upsun will automatically build your application according to the configuration files we created. This process includes installing dependencies, compiling Python files, and starting the FastAPI server.

### 4. Access your application

Once the deployment is complete, you can access your application at the URL provided by the Upsun console or with `upsun url --primary`. You should see the welcome message when you visit the root endpoint.

## Testing the Sentiment Analysis API

Now that our application is deployed, let's test it by sending a request to the sentiment analysis endpoint.

### Using cURL

```bash {filename="Terminal"} theme={null}
curl -X POST $(upsun url --primary --pipe)classification \
     -H "Content-Type: application/json" \
     -d '{"text": "I really enjoyed this movie, it was fantastic!"}'
```

You should receive a response like:

```json theme={null}
{
  "text": "I really enjoyed this movie, it was fantastic!",
  "sentiment": "POSITIVE",
  "confidence": 0.9978765249252319
}
```

### Using the Swagger UI

FastAPI automatically generates interactive API documentation. You can access it by navigating to `/docs` on your application URL:

```bash {filename="Terminal"} theme={null}
open $(upsun url --primary --pipe)docs
```

This will open the Swagger UI where you can test the API through a user-friendly interface.

<img src="https://mintcdn.com/upsun-c9761871/tziXiwEbbKjwbX3l/images/posts/hands-on/pytorch-running-on-upsun/swagger.webp?fit=max&auto=format&n=tziXiwEbbKjwbX3l&q=85&s=56942d3d09357807d9f71421e4b3a73a" alt="Swagger" width="2172" height="1304" data-path="images/posts/hands-on/pytorch-running-on-upsun/swagger.webp" />

## Advanced considerations

### Model size and disk space

The DistilBERT model we're using is relatively small, but if you're working with larger models, you might need to increase the disk space and the memory allocated in the Upsun configuration.

### Performance optimization

For better performance, you might want to:

1. Pre-load the model during the build phase
2. Use model quantization to reduce size
3. Consider implementing caching for frequently requested inputs

## Conclusion

In this tutorial, you've learned how to:

1. Set up a Python application on Upsun
2. Create a FastAPI app with a sentiment analysis endpoint
3. Configure PyTorch (CPU version) for efficient deployment
4. Deploy and test your application

Upsun provides an excellent platform for hosting CPU-based PyTorch applications, with its flexible configuration options and robust scaling capabilities. This approach allows you to deliver machine learning functionality through APIs or in your application without managing complex infrastructure.

Happy coding and machine learning with Upsun!
