PyTorch vs TensorFlow in 2026: Differences, Code Comparison and Which to Choose

pytorch tensorflow сходства и отличия

For years “PyTorch or TensorFlow?” was the first question in any deep learning course. In 2026 the answer has become much clearer. PyTorch is the default framework for research, large language models and most new production systems. TensorFlow is still running in thousands of production systems, but in March 2026 Google announced that it would focus only on security fixes, critical bugs and dependency updates. And the line between the two has blurred: Keras 3 runs the same model code on TensorFlow, PyTorch or JAX.

This guide compares PyTorch and TensorFlow as they are at the end of October 2026: where they came from, how widely each is used, how the code differs, how they handle debugging, compilation, distributed training and deployment, and which one to choose for your project. Every code example below was run with PyTorch 2.14, TensorFlow 2.21 and Keras 3.15, and the outputs are shown as printed.

Key takeaways

  • PyTorch is the default choice in 2026. It is downloaded about five times more often than TensorFlow from PyPI, and about 14 times more models on Hugging Face are tagged PyTorch than TensorFlow.
  • TensorFlow is in maintenance mode. Since March 2026 Google commits only to security and critical bug fixes and dependency updates, and recommends Keras 3, JAX or PyTorch for new generative AI work. Existing TensorFlow systems keep working.
  • The code is now very similar. Both frameworks run eagerly by default, compute gradients automatically and can compile code into fast graphs: torch.compile in PyTorch, tf.function in TensorFlow.
  • Keras 3 is a bridge: one model definition trains on TensorFlow, JAX or PyTorch; in our test all three reached 96–97% accuracy with identical code.
  • For mobile and edge both have mature options: ExecuTorch for PyTorch and LiteRT, the former TensorFlow Lite, which can also run converted PyTorch models.

The short answer

  • Learning deep learning or starting a new project: PyTorch. Most courses, papers, tutorials, open models and job descriptions use it.
  • Working with large language models and generative AI: PyTorch. Hugging Face Transformers v5 supports only PyTorch, and inference engines such as vLLM and SGLang are built on it.
  • Maintaining an existing TensorFlow system: keep it running, it is still supported; plan new components in Keras 3 or PyTorch.
  • You like the high-level Keras API: use Keras 3 and pick the backend, or switch between them.
  • Training on Google TPUs at large scale: JAX is the most natural choice; PyTorch also runs on TPUs through PyTorch/XLA.

PyTorch, TensorFlow, Keras and JAX in 2026

Framework Created by First release Latest version (Oct 2026) Status
PyTorch Meta AI (then Facebook AI Research); governed by the PyTorch Foundation under the Linux Foundation since 2022 2016 2.15 (October 28, 2026) Active development, several feature releases a year
TensorFlow Google Brain November 2015 2.21 (March 2026) Security fixes, critical bug fixes and dependency updates only
Keras François Chollet, now developed at Google 2015; Keras 3 in November 2023 3.15 Active; runs on TensorFlow, JAX or PyTorch
JAX Google 2018 0.12 Active; used by Google DeepMind to train Gemini

The two frameworks started from opposite ideas. TensorFlow 1.x asked you to build a static computation graph first and run it later in a session, which made deployment and optimization easy but debugging painful. PyTorch, inspired by the Lua-based Torch, executed operations immediately like ordinary Python code, which researchers loved. Since then they have converged: TensorFlow 2.0 (2019) made eager execution the default and adopted Keras as its main API, and PyTorch 2.0 (2023) added torch.compile to turn eager code into optimized graphs.

Adoption in numbers

There is no perfect measure of how many people use a framework, but two public ones point the same way:

Bar charts of PyTorch vs TensorFlow adoption in October 2026: PyPI downloads in 30 days PyTorch 59.0M, TensorFlow 11.9M, Keras 11.4M, JAX 8.7M; Hugging Face models PyTorch 242,652, TensorFlow 17,479, JAX 11,941
PyTorch vs TensorFlow adoption: PyPI downloads and Hugging Face models, October 2026
  • PyPI downloads. In the 30 days to October 28, 2026, torch was downloaded 59.0 million times, tensorflow 11.9 million, keras 11.4 million and jax 8.7 million. Downloads include automated installs in CI pipelines, so they overstate the number of people, but the ratio of about five to one is telling.
  • Models on Hugging Face. 242,652 models on the Hub are tagged with the PyTorch library, 17,479 with TensorFlow and 11,941 with JAX. Many newer models are published only as safetensors weights without a framework tag, so the absolute numbers are lower than the total, but almost all of them are loaded with PyTorch.

The ecosystem is moving in the same direction. In December 2025 Hugging Face released Transformers v5 with PyTorch as its only backend, sunsetting TensorFlow and Flax support. Research code has been overwhelmingly PyTorch for years, and the popular LLM training and inference tools, from DeepSpeed and FSDP to vLLM, are PyTorch-based.

Is TensorFlow dead?

Not dead, but no longer evolving. In the TensorFlow 2.21 announcement on March 6, 2026, Google wrote that going forward the team will focus exclusively on security and critical bug fixes, dependency updates (including support for new Python versions) and reviewing critical community contributions. The same applies to related projects such as tf.data, TensorFlow Serving and TFX. For new work in generative AI, Google recommends exploring Keras 3, JAX and PyTorch.

In practice this means:

  • Existing TensorFlow models and pipelines will keep working and receive security updates; there is no need for an emergency migration.
  • Do not expect new features, new model architectures in TensorFlow-specific libraries or support for new hardware beyond what already exists.
  • The on-device part of the former TensorFlow Lite lives on as LiteRT, which is developed separately and actively.
  • New projects that would have used TensorFlow are better started in Keras 3 (keeping the familiar API) or in PyTorch.

The same problem in both frameworks

The 2019 version of this article compared the frameworks on a toy task: find the unknown exponent φ of the function f(x) = xφ from data, using gradient descent.

Formula f(x) = x to the power phi
The function whose exponent we estimate

In 2019 the TensorFlow version needed placeholders, a session and an explicit graph. In 2026 the two versions are almost line for line the same. PyTorch:

import torch

torch.manual_seed(0)
x = torch.rand(1000) * 2                       # inputs
y = x ** 2.5                                   # targets: f(x) = x^phi with the true phi = 2.5

phi = torch.tensor(1.0, requires_grad=True)    # the unknown parameter, initial guess 1.0
optimizer = torch.optim.SGD([phi], lr=0.01, momentum=0.9)

for step in range(1, 201):
    loss = torch.mean((x ** phi - y) ** 2)          # mean squared error
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()
    if step in (1, 25, 50, 100, 200):
        print(f"step {step:3d}  phi = {phi.item():.4f}  loss = {loss.item():.5f}")
step   1  phi = 1.0148  loss = 1.72853
step  25  phi = 2.7988  loss = 0.17768
step  50  phi = 2.4707  loss = 0.00371
step 100  phi = 2.5031  loss = 0.00003
step 200  phi = 2.5000  loss = 0.00000

TensorFlow:

import tensorflow as tf

tf.random.set_seed(0)
x = tf.random.uniform([1000]) * 2
y = x ** 2.5

phi = tf.Variable(1.0)
optimizer = tf.keras.optimizers.SGD(learning_rate=0.01, momentum=0.9)

for step in range(1, 201):
    with tf.GradientTape() as tape:
        loss = tf.reduce_mean((x ** phi - y) ** 2)
    optimizer.apply_gradients([(tape.gradient(loss, phi), phi)])
    if step in (1, 25, 50, 100, 200):
        print(f"step {step:3d}  phi = {phi.numpy():.4f}  loss = {loss.numpy():.5f}")
step   1  phi = 1.0136  loss = 1.57933
step  25  phi = 2.7704  loss = 0.10983
step  50  phi = 2.4311  loss = 0.01033
step 100  phi = 2.5066  loss = 0.00008
step 200  phi = 2.5000  loss = 0.00000

Both find φ = 2.5000 after 200 steps of gradient descent with momentum. The only real difference is how gradients are recorded: PyTorch tracks operations on tensors with requires_grad=True and computes gradients with loss.backward(), while TensorFlow records operations inside a tf.GradientTape block and asks the tape for gradients. Both implement backpropagation automatically. For comparison, the plots from the original 2019 article show the loss and the estimated exponent during training, first in PyTorch, then in TensorFlow 1.x:

Plots of RMSE loss and estimated exponent during training in PyTorch, from the 2019 article
2019: loss and estimated exponent during training in PyTorch
Plots of RMSE loss and estimated exponent during training in TensorFlow 1.x, from the 2019 article
2019: the same in TensorFlow 1.x, which needed more iterations with the optimizer settings used then

A neural network in PyTorch and TensorFlow

A more realistic example: a small fully connected network, a multilayer perceptron with one hidden layer of 128 neurons, that classifies 8×8 images of handwritten digits. Both versions use the same data split, architecture, Adam optimizer, batch size of 32 and 20 epochs. PyTorch, with an explicit training loop:

import torch
from torch import nn
from sklearn.datasets import load_digits
from sklearn.model_selection import train_test_split

torch.manual_seed(0)
X, y = load_digits(return_X_y=True)                      # 1,797 images of digits, 8x8 pixels
X_train, X_test, y_train, y_test = train_test_split(X / 16.0, y, test_size=0.25, random_state=0)
X_train, X_test = torch.tensor(X_train, dtype=torch.float32), torch.tensor(X_test, dtype=torch.float32)
y_train, y_test = torch.tensor(y_train), torch.tensor(y_test)

model = nn.Sequential(nn.Linear(64, 128), nn.ReLU(), nn.Linear(128, 10))
optimizer = torch.optim.Adam(model.parameters(), lr=1e-3)
loss_fn = nn.CrossEntropyLoss()

for epoch in range(20):                                   # the training loop is plain Python
    perm = torch.randperm(len(X_train))
    for i in range(0, len(X_train), 32):
        idx = perm[i:i + 32]
        loss = loss_fn(model(X_train[idx]), y_train[idx])
        optimizer.zero_grad()
        loss.backward()                                   # autograd computes the gradients
        optimizer.step()

model.eval()
with torch.no_grad():
    acc = (model(X_test).argmax(1) == y_test).float().mean().item()
print(f"PyTorch {torch.__version__}: test accuracy {acc:.3f}")
PyTorch 2.14.1+cu130: test accuracy 0.967

TensorFlow, with a custom training step and tf.data:

import tensorflow as tf
from sklearn.datasets import load_digits
from sklearn.model_selection import train_test_split

tf.random.set_seed(0)
X, y = load_digits(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X / 16.0, y, test_size=0.25, random_state=0)
X_train, X_test = X_train.astype("float32"), X_test.astype("float32")

model = tf.keras.Sequential([
    tf.keras.Input(shape=(64,)),
    tf.keras.layers.Dense(128, activation="relu"),
    tf.keras.layers.Dense(10),
])
optimizer = tf.keras.optimizers.Adam(learning_rate=1e-3)
loss_fn = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)
dataset = tf.data.Dataset.from_tensor_slices((X_train, y_train)).shuffle(2000, seed=0).batch(32)

@tf.function                                              # traces the step into a graph for speed
def train_step(xb, yb):
    with tf.GradientTape() as tape:                       # records operations to compute gradients
        loss = loss_fn(yb, model(xb, training=True))
    grads = tape.gradient(loss, model.trainable_variables)
    optimizer.apply_gradients(zip(grads, model.trainable_variables))

for epoch in range(20):
    for xb, yb in dataset:
        train_step(xb, yb)

pred = tf.argmax(model(X_test), axis=1).numpy()
print(f"TensorFlow {tf.__version__}: test accuracy {(pred == y_test).mean():.3f}")
TensorFlow 2.21.0: test accuracy 0.973

The results are the same within noise: 96.7% and 97.3% on the test set. The differences are in style. PyTorch keeps everything in plain Python: you index tensors, call the model, call backward() and step(). TensorFlow uses its own input pipeline (tf.data), separates the training step into a function and compiles it with the @tf.function decorator. In TensorFlow you would usually not write the loop at all and call model.fit() instead, which is exactly what Keras 3 offers on every backend.

Keras 3: one model, three backends

Keras 3 is a high-level API that runs on top of TensorFlow, JAX or PyTorch. You choose the backend with one environment variable before importing Keras, and the model code does not change:

import os
import sys
os.environ["KERAS_BACKEND"] = sys.argv[1]                 # "tensorflow", "jax" or "torch", set before importing keras
import keras
from sklearn.datasets import load_digits
from sklearn.model_selection import train_test_split

keras.utils.set_random_seed(0)
X, y = load_digits(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X / 16.0, y, test_size=0.25, random_state=0)

model = keras.Sequential([
    keras.Input(shape=(64,)),
    keras.layers.Dense(128, activation="relu"),
    keras.layers.Dense(10),
])
model.compile(optimizer=keras.optimizers.Adam(learning_rate=1e-3),
              loss=keras.losses.SparseCategoricalCrossentropy(from_logits=True),
              metrics=["accuracy"])
model.fit(X_train, y_train, epochs=20, batch_size=32, verbose=0)
loss, acc = model.evaluate(X_test, y_test, verbose=0)
print(f"Keras {keras.__version__} on {keras.backend.backend()}: test accuracy {acc:.3f}")

Running the script three times with tensorflow, jax and torch as the argument:

Keras 3.15.1 on tensorflow: test accuracy 0.964
Keras 3.15.1 on jax: test accuracy 0.969
Keras 3.15.1 on torch: test accuracy 0.969

The same twenty lines train the same network on three different frameworks with the same result. A Keras model on the PyTorch backend is also a regular torch.nn.Module, so it can be mixed with PyTorch code, and saved Keras models can be loaded on any backend. For teams with a lot of Keras code this is the easiest way out of TensorFlow: switch the backend, test, and keep the code.

Key differences

PyTorch TensorFlow
Programming style Pythonic, object-oriented: models are nn.Module classes, training loops are written by hand or with Lightning, Hugging Face Accelerate or similar libraries Keras API with model.fit(), or custom loops with GradientTape
Execution Eager by default; torch.compile compiles models into optimized kernels; torch.export captures a full graph for deployment Eager by default; tf.function traces code into graphs, optionally with XLA compilation
Debugging Any Python debugger, print statements, breakpoints inside the model Same in eager mode; inside tf.function graphs debugging is harder and needs tf.config.run_functions_eagerly(True)
Hardware NVIDIA CUDA, AMD ROCm, Apple Silicon (MPS), Intel GPUs; TPUs through PyTorch/XLA NVIDIA GPUs (on Windows only via WSL2 since 2.11), Google TPUs; other hardware through plugins
Distributed training DDP, FSDP2, tensor and pipeline parallelism, DeepSpeed, Megatron; standard for LLM training tf.distribute strategies, mature for data parallelism on GPUs and TPUs
Models and libraries Hugging Face Transformers and Diffusers, timm, torchvision, vLLM, SGLang and most open-source LLM tooling Kaggle Models (formerly TensorFlow Hub), KerasHub, TFX for production pipelines
Visualization TensorBoard (through torch.utils.tensorboard), Weights & Biases, MLflow TensorBoard, now installed separately since TensorFlow 2.21
Serving vLLM and SGLang for LLMs, NVIDIA Triton, Ray Serve, ONNX Runtime; TorchServe is no longer actively maintained TensorFlow Serving, in maintenance like the rest of TensorFlow
Mobile and edge ExecuTorch (1.0 since October 2025) LiteRT (formerly TensorFlow Lite)
Development Active, new release every few months Maintenance only since March 2026

Speed is not on the list on purpose. For the same model on the same GPU, both frameworks call the same NVIDIA libraries (cuDNN, cuBLAS), and differences in published benchmarks usually come from the model implementation, data loading or compilation settings rather than from the framework itself. Choose by ecosystem and workflow, not by benchmark charts.

Deployment, mobile and edge

Deployment used to be TensorFlow’s strongest argument: in 2019 TensorFlow Serving and TensorFlow Lite had no real equivalent in PyTorch. That gap has closed.

  • Servers. PyTorch models are deployed with torch.export and AOTInductor, NVIDIA Triton Inference Server, ONNX Runtime after export to ONNX, or with specialized LLM engines like vLLM and SGLang. TorchServe, PyTorch’s own model server, is in limited maintenance. TensorFlow Serving still works well for existing TensorFlow models.
  • Mobile and embedded. ExecuTorch, PyTorch’s on-device runtime, reached version 1.0 in October 2025; Meta uses it in Instagram, WhatsApp, Messenger and Facebook and in its smart glasses. LiteRT, the renamed TensorFlow Lite, is actively developed by Google, offers GPU and NPU acceleration and can run models converted from PyTorch with Google’s AI Edge Torch converter.
  • Browser. TensorFlow.js remains an option for TensorFlow and Keras models; ONNX Runtime Web runs exported PyTorch models.

The ONNX format is the common denominator: most PyTorch and TensorFlow models can be exported to ONNX and run with ONNX Runtime on servers, phones and in the browser.

What about JAX?

JAX is Google’s third framework and its main one for research: Google DeepMind trains Gemini with JAX and the Pathways system on TPUs. JAX looks like NumPy, but every function can be differentiated with jax.grad, compiled with jax.jit and parallelized across many accelerators. Neural network libraries such as Flax and Keras 3 run on top of it.

JAX shines on TPUs and in large-scale training where its compiler and parallelism primitives pay off. It has a smaller community, fewer ready-made models and a steeper learning curve than PyTorch, because it requires a functional style: no in-place updates, explicit random keys, pure functions. For most practitioners in 2026 the choice is between PyTorch and Keras 3, with JAX as a specialized tool for TPUs and frontier-scale research.

Which framework should you choose?

  1. Students and beginners: PyTorch. You will find more tutorials, courses and answers, and the skills transfer directly to research and industry. Start with our guide to convolutional neural networks, recurrent networks and LSTM, all with PyTorch code.
  2. Researchers: PyTorch, or JAX if you work on TPUs or need its functional transformations.
  3. LLM and generative AI developers: PyTorch: Hugging Face, vLLM, fine-tuning libraries and almost all open models assume it.
  4. Teams with TensorFlow in production: keep maintaining it; write new models in Keras 3 so that you can switch the backend later; migrate when a system needs major changes anyway.
  5. Mobile developers: either works: ExecuTorch for PyTorch models, LiteRT for TensorFlow and converted PyTorch models.

Hardware matters too: whichever framework you choose, training speed depends mostly on the GPU and its memory. See our guide to the best GPU for AI.

What has changed since 2018

The first version of this article, translated from a 2018 comparison by Kirill Dobovikov, listed five differences. Here is how each looks in 2026:

Difference in 2018 In 2026
Popularity: TensorFlow is the standard, PyTorch is new and in beta Reversed: PyTorch leads by a wide margin, TensorFlow is in maintenance
Dynamic (PyTorch) vs static (TensorFlow) graphs Both eager by default, both can compile to graphs
Debugging: any Python tool in PyTorch, special tfdbg in TensorFlow Standard Python debugging works in both in eager mode
Visualization: TensorBoard vs visdom TensorBoard works with both; Weights & Biases and MLflow are common too
Deployment: TensorFlow clearly ahead Comparable: ExecuTorch and LiteRT on devices, many serving options for both

In 2018, debugging TensorFlow graphs required its own debugger, tfdbg, with a terminal interface:

Terminal interface of tfdbg, the TensorFlow 1.x debugger
tfdbg, the TensorFlow 1.x debugger, in 2018

FAQ

Is PyTorch better than TensorFlow?

For most new projects in 2026, yes: it has a much larger community, most new models and tools, active development and a more Pythonic style. TensorFlow is still a solid, stable choice for systems already built on it and for its mature serving and pipeline tools, but it no longer receives new features.

Is TensorFlow still used in 2026?

Yes, widely, mostly in existing production systems. It was downloaded about 12 million times from PyPI in the last month. Since March 2026 Google maintains it with security fixes and dependency updates and points new generative AI projects to Keras 3, JAX and PyTorch.

Should I learn PyTorch or TensorFlow first?

PyTorch. The concepts — tensors, automatic differentiation, layers, optimizers, training loops — are the same in both, so moving to TensorFlow or Keras later takes days, not months.

Is PyTorch faster than TensorFlow?

Not in general. On the same GPU both use the same NVIDIA libraries, and well-written code runs at similar speed. Compilation (torch.compile or XLA), mixed precision and data loading matter far more than the framework.

What is the difference between Keras and TensorFlow?

Keras is a high-level API for building and training models; TensorFlow is a full framework with its own tensors, automatic differentiation and deployment tools. Keras was TensorFlow’s official API, and since Keras 3 it is independent again and runs on TensorFlow, JAX or PyTorch.

Can I convert a TensorFlow model to PyTorch?

There is no automatic one-click conversion, but there are practical routes: run Keras models on the PyTorch backend of Keras 3, export the model to ONNX and run it with ONNX Runtime, or load the weights into an equivalent PyTorch architecture. For popular architectures Hugging Face usually already has PyTorch weights.


bnr2mob
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted