¿Qué es un tensor?
Un tensor es la estructura de datos fundamental en TensorFlow. Se puede entender como una generalización de los arrays de NumPy a múltiples dimensiones: un escalar es un tensor de rango 0, un vector es un tensor de rango 1, una matriz es un tensor de rango 2, y así sucesivamente.
Los tensores tienen tres propiedades básicas:
| Propiedad | Descripción | Ejemplo | |---|---|---| | rank | Número de dimensiones | 2 para una matriz | | shape | Tamaño de cada dimensión | (3, 4) para una matriz 3×4 | | dtype | Tipo de dato de los elementos | float32, int32, bool, string |
Creación de tensores con tf.constant
tf.constant crea tensores inmutables (no se pueden modificar después de su creación):
import tensorflow as tf
# Escalar (rango 0)
escalar = tf.constant(42)
print(f"Escalar: {escalar}")
print(f"Rank: {tf.rank(escalar)}")
print(f"Shape: {escalar.shape}")
print(f"Dtype: {escalar.dtype}")
# Vector (rango 1)
vector = tf.constant([1.0, 2.0, 3.0, 4.0])
print(f"\nVector: {vector}")
print(f"Shape: {vector.shape}")
# Matriz (rango 2)
matriz = tf.constant([[1, 2, 3],
[4, 5, 6]])
print(f"\nMatriz:\n{matriz}")
print(f"Shape: {matriz.shape}")
# Tensor 3D (rango 3)
tensor_3d = tf.constant([[[1, 2], [3, 4]],
[[5, 6], [7, 8]]])
print(f"\nTensor 3D shape: {tensor_3d.shape}")
Tensores de tipos específicos
import tensorflow as tf
# Especificar dtype explícitamente
entero = tf.constant(10, dtype=tf.int32)
flotante = tf.constant(3.14, dtype=tf.float64)
booleano = tf.constant(True, dtype=tf.bool)
texto = tf.constant("hola TensorFlow", dtype=tf.string)
print(f"int32: {entero.dtype}")
print(f"float64: {flotante.dtype}")
print(f"bool: {booleano.dtype}")
print(f"string: {texto.dtype}")
# Conversión de tipos (casting)
entero_a_float = tf.cast(entero, dtype=tf.float32)
print(f"\nCast a float32: {entero_a_float}")
tf.Variable: tensores mutables
tf.Variable crea tensores cuyo valor puede modificarse durante el entrenamiento. Son los pesos y sesgos del modelo:
import tensorflow as tf
# Crear una variable
peso = tf.Variable(tf.random.normal([3, 3]))
sesgo = tf.Variable(tf.zeros([3]))
print(f"Peso:\n{peso}")
print(f"Sesgo: {sesgo}")
print(f"Es entrenble: {peso.trainable}")
# Modificar el valor de una variable
peso.assign(tf.ones([3, 3]))
print(f"\nPeso tras assign:\n{peso}")
# Modificar in-place con += y -=
sesgo.assign_add([0.1, 0.2, 0.3])
print(f"Sesgo tras assign_add: {sesgo}")
Tensores especiales: zeros, ones, eye y random
import tensorflow as tf
# Tensor de ceros
ceros = tf.zeros([2, 3])
print(f"Ceros:\n{ceros}")
# Tensor de unos
unos = tf.ones([2, 3], dtype=tf.int32)
print(f"\nUnos:\n{unos}")
# Tensor con valor constante
lleno = tf.fill([2, 3], value=7.0)
print(f"\nLleno de 7:\n{lleno}")
# Matriz identidad
identidad = tf.eye(4)
print(f"\nIdentidad 4x4:\n{identidad}")
# Tensores aleatorios
normal = tf.random.normal([3, 3], mean=0, stddev=1)
uniforme = tf.random.uniform([3, 3], minval=0, maxval=1)
print(f"\nNormal:\n{normal}")
print(f"\nUniforme:\n{uniforme}")
# Fijar semilla para reproducibilidad
tf.random.set_seed(42)
reproducible = tf.random.normal([2, 2])
print(f"\nReproducible:\n{reproducible}")
Operaciones aritméticas elementales
import tensorflow as tf
a = tf.constant([[1.0, 2.0], [3.0, 4.0]])
b = tf.constant([[5.0, 6.0], [7.0, 8.0]])
# Suma elemento a elemento
suma = tf.add(a, b)
suma_op = a + b # equivalente con operador
print(f"Suma:\n{suma}")
# Resta
resta = tf.subtract(a, b)
print(f"\nResta:\n{resta}")
# Multiplicación elemento a elemento (no es producto matricial)
producto_elem = tf.multiply(a, b)
print(f"\nProducto elemento a elemento:\n{producto_elem}")
# División
division = tf.divide(a, b)
print(f"\nDivisión:\n{division}")
# Potencia
potencia = tf.pow(a, 2)
print(f"\nCuadrado:\n{potencia}")
# Raíz cuadrada
raiz = tf.sqrt(a)
print(f"\nRaíz cuadrada:\n{raiz}")
Álgebra lineal: producto matricial y más
import tensorflow as tf
A = tf.constant([[1.0, 2.0], [3.0, 4.0]])
B = tf.constant([[5.0, 6.0], [7.0, 8.0]])
# Producto matricial (matrix multiplication)
producto = tf.matmul(A, B)
producto_op = A @ B # equivalente con operador @
print(f"Producto matricial:\n{producto}")
# Transpuesta
transpuesta = tf.transpose(A)
print(f"\nTranspuesta:\n{transpuesta}")
# Determinante
det = tf.linalg.det(A)
print(f"\nDeterminante: {det}")
# Inversa
inversa = tf.linalg.inv(A)
print(f"\nInversa:\n{inversa}")
# Norma de un vector
v = tf.constant([3.0, 4.0])
norma = tf.norm(v)
print(f"\nNorma L2 de {v.numpy()}: {norma}")
Manipulación de formas (reshape, expand_dims, squeeze)
import tensorflow as tf
original = tf.constant([1, 2, 3, 4, 5, 6])
print(f"Original shape: {original.shape}")
# Cambiar forma (reshape)
matriz = tf.reshape(original, [2, 3])
print(f"\nReshape a (2,3):\n{matriz}")
tensor_3d = tf.reshape(original, [1, 2, 3])
print(f"\nReshape a (1,2,3):\n{tensor_3d}")
# Añadir dimensión (expand_dims)
vector = tf.constant([1.0, 2.0, 3.0])
fila = tf.expand_dims(vector, axis=0) # (1, 3) - vector fila
columna = tf.expand_dims(vector, axis=1) # (3, 1) - vector columna
print(f"\nVector shape: {vector.shape}")
print(f"Fila shape: {fila.shape}")
print(f"Columna shape: {columna.shape}")
# Eliminar dimensiones de tamaño 1 (squeeze)
tensor_con_dim1 = tf.constant([[[1.0], [2.0], [3.0]]])
print(f"\nAntes de squeeze: {tensor_con_dim1.shape}")
comprimido = tf.squeeze(tensor_con_dim1)
print(f"Después de squeeze: {comprimido.shape}")
Indexación y slicing
import tensorflow as tf
tensor = tf.constant([[10, 20, 30],
[40, 50, 60],
[70, 80, 90]])
# Acceso a elemento individual
print(f"Elemento [1,2]: {tensor[1, 2]}")
# Fila completa
print(f"Fila 0: {tensor[0]}")
# Columna completa
print(f"Columna 1: {tensor[:, 1]}")
# Submatriz
print(f"Submatriz [0:2, 1:3]:\n{tensor[0:2, 1:3]}")
# Indexación booleana con tf.boolean_mask
mascara = tf.constant([True, False, True])
seleccionados = tf.boolean_mask(tensor, mascara, axis=0)
print(f"\nFilas seleccionadas:\n{seleccionados}")
Operaciones de reducción
import tensorflow as tf
datos = tf.constant([[1.0, 2.0, 3.0],
[4.0, 5.0, 6.0]])
# Suma total
print(f"Suma total: {tf.reduce_sum(datos)}")
# Suma por columnas (axis=0)
print(f"Suma por columnas: {tf.reduce_sum(datos, axis=0)}")
# Suma por filas (axis=1)
print(f"Suma por filas: {tf.reduce_sum(datos, axis=1)}")
# Media
print(f"Media total: {tf.reduce_mean(datos)}")
# Máximo y mínimo
print(f"Máximo: {tf.reduce_max(datos)}")
print(f"Mínimo: {tf.reduce_min(datos)}")
# Índice del máximo (argmax)
print(f"Argmax eje 1: {tf.argmax(datos, axis=1)}")
print(f"Argmin eje 0: {tf.argmin(datos, axis=0)}")
Eager execution: ejecución inmediata
Desde TensorFlow 2.x, la eager execution está activada por defecto. Esto significa que las operaciones se ejecutan inmediatamente al llamarlas, devolviendo tensores con valores concretos en lugar de nodos de un grafo:
import tensorflow as tf
# Comprueba que eager está activado (True por defecto en TF 2.x)
print(f"Eager execution: {tf.executing_eagerly()}")
# Las operaciones devuelven tensores con valor inmediato
x = tf.constant(3.0)
y = tf.constant(4.0)
z = x * y + tf.sqrt(x)
print(f"Resultado: {z}") # Se imprime el valor, no un símbolo de grafo
# Convertir a numpy fácilmente
print(f"Como numpy: {z.numpy()}")
print(f"Tipo Python: {float(z)}")
Para operaciones que necesitan rendimiento máximo (p. ej. durante el entrenamiento), se puede compilar una función con @tf.function, que construye un grafo estático internamente:
import tensorflow as tf
@tf.function
def funcion_compilada(x, y):
return tf.matmul(x, y) + tf.reduce_sum(x)
A = tf.constant([[1.0, 2.0], [3.0, 4.0]])
B = tf.constant([[5.0, 6.0], [7.0, 8.0]])
resultado = funcion_compilada(A, B)
print(f"Resultado compilado:\n{resultado}")
Broadcasting: operaciones con formas diferentes
TensorFlow admite broadcasting al estilo NumPy: cuando dos tensores tienen formas incompatibles, el de menor dimensión se "expande" automáticamente:
import tensorflow as tf
# Suma de una matriz y un vector (broadcasting)
matriz = tf.constant([[1.0, 2.0, 3.0],
[4.0, 5.0, 6.0]]) # shape (2, 3)
vector = tf.constant([10.0, 20.0, 30.0]) # shape (3,)
resultado = matriz + vector # el vector se expande a (2, 3)
print(f"Broadcasting suma:\n{resultado}")
# Multiplicación de una matrix por un escalar
escalar = tf.constant(2.0)
doble = matriz * escalar
print(f"\nMultiplicación por escalar:\n{doble}")
Concatenación y apilado de tensores
import tensorflow as tf
a = tf.constant([[1, 2], [3, 4]])
b = tf.constant([[5, 6], [7, 8]])
# Concatenar en eje 0 (añadir filas)
concat_filas = tf.concat([a, b], axis=0)
print(f"Concat eje 0 (shape {concat_filas.shape}):\n{concat_filas}")
# Concatenar en eje 1 (añadir columnas)
concat_cols = tf.concat([a, b], axis=1)
print(f"\nConcat eje 1 (shape {concat_cols.shape}):\n{concat_cols}")
# Apilar creando nueva dimensión
apilado = tf.stack([a, b], axis=0) # shape (2, 2, 2)
print(f"\nStack eje 0 (shape {apilado.shape}):\n{apilado}")
Alan Sastre
Ingeniero de Software y formador, CEO en CertiDevs
Ingeniero de software especializado en Full Stack y en Inteligencia Artificial. Como CEO de CertiDevs, TensorFlow es una de sus áreas de expertise. Con más de 15 años programando, 6K seguidores en LinkedIn y experiencia como formador, Alan se dedica a crear contenido educativo de calidad para desarrolladores de todos los niveles.
Más tutoriales de TensorFlow
Explora más contenido relacionado con TensorFlow y continúa aprendiendo con nuestros tutoriales gratuitos.
Aprendizajes de esta lección
Crear tensores con tf.constant, tf.Variable y tf.zeros/ones. Comprender rangos (rank), formas (shape) y tipos de dato (dtype). Realizar operaciones aritméticas y de álgebra lineal con tensores. Manipular formas con reshape, expand_dims, squeeze y transpose. Entender qué es eager execution y cómo facilita la depuración.