In the two previous lessons you built the same gradient and the same MNIST network in TensorFlow/Keras and in PyTorch, and confirmed that they reach the same result. Now comes the question everyone asks sooner or later — and that the TecnoMarket team has written on their whiteboard: which one should you choose? This lesson answers honestly: no camps, just criteria. We will compare philosophy, learning curve, debugging, ecosystems and real-world adoption; we will put the same mini-model side by side; we will briefly introduce the other players in the landscape (JAX, Hugging Face, ONNX); and we will close with a practical decision guide. Spoiler for the ending: the choice matters less than it seems, because what is valuable — the concepts you have spent five modules learning — is transferable.

Contents

  1. Two philosophies, one goal
  2. Learning curve and debugging
  3. Ecosystems: what surrounds each framework
  4. Adoption: industry vs. research
  5. Performance: the practical tie
  6. Detailed comparison table
  7. The same model, side by side
  8. Other players in the landscape
  9. Decision guide: for you and for TecnoMarket

Two philosophies, one goal

If we had to sum up each framework in one sentence:

  • TensorFlow/Keras: "the common case should be trivial". Optimized for the standard path: define, compile, train, deploy. Born at Google (2015) with large-scale production in mind.
  • PyTorch: "everything should be visible". Optimized for experimentation: every training step is in your code, ready to modify. Born at Meta (2017) with research in mind.

Neither philosophy is superior; they answer different needs. The course analogy: Keras is the appliance with preset programs; PyTorch is the professional kitchen where you control every burner. For 90% of dishes the result is the same; for the experimental 10% (a GAN with a custom loop like the one in 05-01, an exotic loss, a freshly published paper), the professional kitchen is a blessing — although Keras also lets you drop down to that level with GradientTape, as you saw in 06-01, it is simply not its default path.

Learning curve and debugging

Learning curve. Keras wins in the first hours: your first network in 02-05 was five lines (Sequential, compile, fit). In PyTorch that same network requires understanding nn.Module, DataLoader and the five-step loop before you see a single result. But the curves cross: the PyTorch user understands what is going on sooner (because they wrote it), while the Keras user can take longer to escape the "magic" of fit(). This course deliberately followed that order: first productivity with Keras, then transparency with PyTorch.

Debugging. Here PyTorch has a structural advantage thanks to define-by-run: the forward pass is normal Python code, so you can put print(x.shape) inside forward(), step through with your IDE's debugger, and inspect any intermediate tensor. In TensorFlow, eager mode (the one you used in 06-01) allows the same, but when Keras compiles the model into a graph for speed (tf.function, which fit() applies by default), errors arrive wrapped in long, less readable tracebacks. Practical translation: in Keras you debug mostly by reading messages; in PyTorch you debug by executing line by line.

Ecosystems: what surrounds each framework

A framework is not just its API: it is everything built around it.

The TensorFlow ecosystem: strong at deployment

Piece What it is for
TFLite (LiteRT) Running models on phones and embedded devices (Android, iOS, microcontrollers)
TF.js Running and training models in the browser, in JavaScript
TF Serving High-performance model server for production
TFX Complete production ML pipelines (data validation, training, deployment)
TensorBoard Training visualization (you will use it in 06-04; it also works with PyTorch)

The common thread: bringing the model to where the user is. We will cover deployment in detail in 06-05.

The PyTorch ecosystem: strong at models and research

Piece What it is for
torchvision / torchaudio / torchtext Datasets, transforms and pretrained models per domain
transformers (Hugging Face) Thousands of pretrained models (BERT, GPT and family — the ones from 05-05) ready for fine-tuning
PyTorch Lightning Structures the explicit training loop (recovers part of fit()'s convenience)
TorchServe Model server (equivalent to TF Serving)

The common thread: immediate access to the latest. When a paper comes out, its code is usually PyTorch; when an open language model comes out, it is on Hugging Face. Important note: Hugging Face also supports TensorFlow for many models, but its first-class citizen is PyTorch.

Adoption: industry vs. research

The broad strokes, without percentages that go stale:

  • Research: PyTorch has clearly dominated since ~2020. At the major conferences (NeurIPS, ICML, CVPR), the vast majority of published implementations are PyTorch. If your job is reproducing papers, PyTorch is nearly mandatory.
  • Industry: much more evenly split. TensorFlow has an enormous installed base (especially at companies that built their infrastructure between 2016 and 2020, and on mobile/edge thanks to TFLite), while PyTorch grows strongly, pushed by the LLM boom and Hugging Face.
  • Job postings: most deep learning positions cite both, or "either one". Knowing both — like you now — is the most comfortable position.

Performance: the practical tie

Which trains faster? Honest answer: a practical tie. Both delegate the heavy lifting to the same NVIDIA libraries (cuDNN) for GPUs; both compile graphs to optimize (TF with tf.function, PyTorch with torch.compile); and benchmarks flip back and forth depending on model, hardware and version. The typical differences (±10%) are smaller than the effect of a good data pipeline (the prefetch from 06-01) or a sensible batch size. Conclusion: do not choose a framework for speed; choose for your team, the ecosystem and the model's destination.

Detailed comparison table

Criterion TensorFlow / Keras PyTorch
Creator and year Google, 2015 Meta, 2017
Philosophy High-level by default, production Explicit by default, research
Model definition Sequential / functional / subclassing Subclassing (nn.Module) as the norm
Training loop Automatic fit() (GradientTape if you want control) Always explicit (Lightning if you want structure)
Initial curve Very gentle (5 lines and you train) More demanding (5-step loop)
Debugging Good in eager; harsh tracebacks in graph mode Excellent: pure Python, standard debugger
Data tf.data (map/shuffle/batch/prefetch) Dataset + DataLoader
Mobile / browser TFLite, TF.js (very mature) ExecuTorch (more recent)
Serving in production TF Serving, TFX TorchServe, generic servers (FastAPI)
Pretrained models Keras Applications (the MobileNetV2 from 05-03), TF Hub torchvision, Hugging Face (huge)
Research community A minority today Dominant
Enterprise installed base Very large Large and growing
Performance Equivalent Equivalent
What you already did in the course All of modules 2–5 plus 06-01 06-02 (MNIST rewritten)

The same model, side by side

You already saw the snippets in 06-01 and 06-02; here they are condensed for a single glance. The 784-128-64-10 network from 02-05:

# ---------- KERAS ----------
from tensorflow import keras

model = keras.Sequential([
    keras.layers.Dense(128, activation="relu"),
    keras.layers.Dense(64, activation="relu"),
    keras.layers.Dense(10, activation="softmax"),
])
model.compile(optimizer="adam",
              loss="sparse_categorical_crossentropy",
              metrics=["accuracy"])
model.fit(x_train, y_train, epochs=5, batch_size=32)
# ---------- PYTORCH ----------
import torch
from torch import nn

class MNISTNet(nn.Module):
    def __init__(self):
        super().__init__()
        self.net = nn.Sequential(          # yes, PyTorch also has Sequential
            nn.Linear(784, 128), nn.ReLU(),
            nn.Linear(128, 64), nn.ReLU(),
            nn.Linear(64, 10))             # logits, no softmax (see 06-02)

    def forward(self, x):
        return self.net(x)

model = MNISTNet()
loss_fn = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)

for epoch in range(5):
    for x, y in train_loader:
        logits = model(x.view(x.size(0), -1))
        loss = loss_fn(logits, y)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

Reading the side-by-side:

  • The model definition is almost a carbon copy (note nn.Sequential: for linear stacks, PyTorch also offers a shortcut).
  • The difference is in the training: 3 lines (compile + fit) versus ~10 (the loop). That is, in essence, the whole framework debate condensed onto one screen.
  • And the two "detail" differences you already know: softmax on the output (Keras) vs. raw logits (PyTorch), and the explicit flatten.

Other players in the landscape

The world does not end at TF and PyTorch. Three names worth placing on the map:

Player What it is When you will run into it
JAX Google library: numpy + automatic differentiation + XLA compilation. Pure functional style Cutting-edge research and giant models; Keras 3 can use it as a backend
Hugging Face Not a competitor: it is an upper layer with thousands of pretrained models (the transformers from 05-05) and datasets, on top of PyTorch (mainly) and TF As soon as you want to use a BERT/GPT without training it yourself (you will in 07-05)
ONNX Not a framework: it is a model interchange format. You export from PyTorch, run on any compatible runtime As a bridge between frameworks and toward production; we will use it in 06-05

Final mention: Keras 3 is now multi-backend — the same Keras code can run on TensorFlow, JAX or even PyTorch. The border between frameworks blurs year after year, one more reason not to obsess over the choice.

Decision guide: for you and for TecnoMarket

Questions that actually decide (in order of weight):

  1. What does your team / your company use? The best framework is the one used by the people who will help you and the code you will inherit.
  2. Will you start from pretrained models from recent research (LLMs, diffusion, the latest from Hugging Face)? → PyTorch will give you less friction.
  3. Is the destination mobile, browser or edge? → TensorFlow's TFLite/TF.js ecosystem remains the most mature.
  4. Do you prioritize fast prototyping of standard workflows (classification, regression, transfer learning like 05-03)? → Keras is hard to beat.
  5. Do you need custom training loops (GANs like 05-01, multiple losses, research)? → PyTorch's explicit style feels more natural.

TecnoMarket's decision. The data team debates it and decides:

  • Keras/TensorFlow as the production base: their current systems (the photo classifier with MobileNetV2 from 05-03, the review classifier from 04-03, the demand forecasting from 04-04) are already written in Keras, they work, and the plan to bring the product classifier to the warehouse staff's mobile app fits TFLite.
  • PyTorch as the exploration tool: the project to generate promotional descriptions and images (module 7) will start from Hugging Face models, and there PyTorch is the short path.
  • Team rule: every model that goes to production is validated against the same frozen test set, whatever the framework — and ONNX is noted down as the bridge if a model ever needs to move from one world to the other (we will see it in 06-05).

It is a pragmatic decision, not a religious one. And it is the same one we recommend to you: go deep in one, stay functional in the other.

Common Mistakes and Tips

  • Choosing by headlines ("X is dead", "everyone uses Y"): both frameworks have active development, enormous communities and years of future ahead. Decide based on your context, not on Twitter.
  • Switching frameworks mid-project: the cost of migrating (rewriting, revalidating, retraining the team) almost never pays off against a marginal advantage. Finish with what you started; migrate, if at all, between projects.
  • Learning the framework instead of the concepts: whoever understands backprop (02-03), regularization (05-04) or attention (05-05) switches frameworks in days; whoever only memorized APIs starts from scratch. Invest in concepts.
  • Comparing performance with other people's benchmarks: if you truly care about speed, measure your model with your data on your hardware. Generic benchmarks do not capture your case.
  • Tip: reading code in the "other" framework is a great exercise. With the equivalence tables from 06-02 you can mentally translate almost any example, and that doubles the documentation and tutorials within your reach.

Exercises

Exercise 1: mental translation

Without running anything, match each Keras element with its PyTorch equivalent: (a) model.fit(...), (b) Dense(64, activation="relu"), (c) tf.data.Dataset with shuffle().batch(), (d) model.evaluate(...), (e) compile(optimizer="adam", loss=...).

Exercise 2: reasoned recommendation

Three scenarios; for each, recommend a framework and justify it in 2-3 lines using the decision guide criteria: (1) a startup wants to detect manufacturing defects with an Android tablet camera inside the factory itself, offline; (2) a university group wants to modify the attention mechanism of a transformer published last month; (3) TecnoMarket wants a standard support-ticket classifier in 2 weeks, with a team that has only taken this course.

Exercise 3: reading the other language

This PyTorch snippet reaches you from a paper. Describe it in "Keras language": what model is it and how would you write it with Sequential?

class Net(nn.Module):
    def __init__(self):
        super().__init__()
        self.fc1 = nn.Linear(20, 8)
        self.drop = nn.Dropout(0.3)
        self.fc2 = nn.Linear(8, 1)

    def forward(self, x):
        x = torch.relu(self.fc1(x))
        x = self.drop(x)
        return self.fc2(x)

Solutions

Solution 1:

  • (a) fit() → the complete explicit loop: for epoch → forward → loss → zero_grad → backward → step.
  • (b) Dense(64, activation="relu") → nn.Linear(in_features, 64) followed by nn.ReLU() (in PyTorch the input is explicit and the activation goes separately).
  • (c) tf.data with shuffle().batch() → DataLoader(dataset, batch_size=..., shuffle=True).
  • (d) evaluate() → a loop with model.eval() + torch.no_grad() computing metrics by hand.
  • (e) compile(...) → creating torch.optim.Adam(model.parameters()) and the loss function (nn.CrossEntropyLoss(), etc.) as standalone objects.

Solution 2:

  1. TensorFlow/Keras: an offline edge/mobile destination → TFLite is the most mature ecosystem for Android (criterion 3). They would train with Keras (probably transfer learning as in 05-03) and export to TFLite.
  2. PyTorch: reproducing and modifying a recent paper → the published code will almost surely be PyTorch (criterion 2), and the explicit loop makes it easier to touch the model's internals (criterion 5).
  3. Keras: standard workflow, short deadline, a team trained in this course where Keras is the main language (criteria 1 and 4). TextVectorization + dense network as in 04-03, and off to production.

Solution 3: It is a binary MLP with dropout (like the ones in 05-04): a 20-feature input, a hidden layer of 8 with ReLU, 30% dropout and an output of 1 logit (the loss would be BCEWithLogitsLoss). In Keras:

model = keras.Sequential([
    keras.layers.Dense(8, activation="relu", input_shape=(20,)),
    keras.layers.Dropout(0.3),
    keras.layers.Dense(1, activation="sigmoid"),   # or no sigmoid + from_logits=True
])

One nuance: the usual Keras version puts a sigmoid on the output and uses plain BinaryCrossentropy; the exact equivalence with the PyTorch snippet (raw logit) would be no final activation plus from_logits=True.

Conclusion

You now have the full comparison: Keras/TensorFlow shines in productivity and deployment (TFLite, TF.js, TF Serving); PyTorch shines in transparency, debugging and research (Hugging Face, papers); performance is a practical tie; and around them orbit JAX, Hugging Face as an upper layer, and ONNX as a bridge format. TecnoMarket chose pragmatically: Keras for their existing production, PyTorch for exploring pretrained models, and shared validation for everything. The underlying lesson is the one that closes the debate: the course's concepts — tensors, gradients, layers, regularization, attention — are transferable; the framework is a tool, and you already handle the two main ones.

Before taking anything to production, the environment you work in needs to be professionalized: in the next lesson we will step out of the notebook — local and cloud GPUs, project structure, reproducibility, version control for ML and monitoring with TensorBoard — so that the TecnoMarket team's work stops living in loose Colab tabs.

© Copyright 2026. All rights reserved