Tensor Flow 📂 Data Pipelines and Good Training · 1 of 6 31 min read

tf.data.Dataset Basics: Load Data From Tensors, CSV and Files

Learn what a tf.data.Dataset is and how to build one from NumPy arrays, dicts, Python generators, CSV files and folders of images. Compare from_tensor_slices with from_tensors, read CSVs with make_csv_dataset and decode_csv, and load PNG files by path. Try the Slicer and the CSV playground to see every element live.

Section 01

The Story — The Factory Conveyor Belt

Parts Arrive One at a Time
A car factory does not dump every part for a year on the workers' desks. Parts arrive on a conveyor belt, a few at a time, just when they are needed. The belt can bring parts from the store room, from a truck, or from another factory.

tf.data.Dataset is TensorFlow's conveyor belt. It brings training examples to your model one piece (or one batch) at a time. The examples can come from arrays in memory, from CSV files, from folders of images, or from special TFRecord files. Your data can be far bigger than your computer's memory, and it still works.

So far we fed tensors straight into the model. Real projects need more: reading files, shuffling, batching, and doing it fast. This module covers the whole pipeline and the habits of good training. This first lesson is about where data comes from.

Animated Diagram — Many Sources, One Belt
NumPy / tensors CSV files image folders tf.data.Dataset — one element at a time model

Whatever the source, the model sees the same thing: a stream of elements with a fixed structure.


Section 02

From Tensors and Arrays

from_tensor_slices cuts along the first axis: 5 rows become 5 elements. Tuples and dicts are cut in step, so each feature stays with its label.

import tensorflow as tf
import numpy as np

features = np.arange(15, dtype="float32").reshape(5, 3)   # 5 samples, 3 features
labels = np.array([0, 1, 0, 1, 1])

ds = tf.data.Dataset.from_tensor_slices((features, labels))
print(ds.element_spec)
print("number of elements:", ds.cardinality().numpy())
for x, y in ds.take(2):
    print("x =", x.numpy(), " y =", y.numpy())
OUTPUT
(TensorSpec(shape=(3,), dtype=tf.float32, name=None), TensorSpec(shape=(), dtype=tf.int64, name=None)) number of elements: 5 x = [0. 1. 2.] y = 0 x = [3. 4. 5.] y = 1
from_tensor_slices(t)
Slices along axis 0
(5, 3) → 5 elements of shape (3,)
The usual choice for data
from_tensors(t)
Does not slice
(5, 3) → 1 element of shape (5, 3)
A common beginner mistake
dict_ds = tf.data.Dataset.from_tensor_slices({"age": [25, 32, 47], "city": ["Delhi", "Pune", "Baddi"]})
for row in dict_ds:
    print(int(row["age"]), row["city"].numpy().decode())

print("range      :", [int(v) for v in tf.data.Dataset.range(3, 9, 2)])

def gen():                                      # any Python generator
    for i in range(3):
        yield i, i * i
gen_ds = tf.data.Dataset.from_generator(gen, output_signature=(
    tf.TensorSpec([], tf.int32), tf.TensorSpec([], tf.int32)))
print("generator  :", [(int(a), int(b)) for a, b in gen_ds])
OUTPUT
25 Delhi 32 Pune 47 Baddi range : [3, 5, 7] generator : [(0, 0), (1, 1), (2, 4)]

Section 03

Try It — The Slicer

🔪 How Will My Data Be Cut Into Elements? Interactive

Set the shape of your features and labels. Choose the function. Press Slice and watch the rows fly onto the belt. Try giving labels a different first size to see the error.


Section 04

From CSV Files

First we write a small CSV file, so the example runs anywhere.

csv_text = """age,income,city,bought
25,32000,Delhi,0
32,58000,Pune,1
47,91000,Baddi,1
51,40000,Delhi,0
38,75000,Pune,1
29,28000,Baddi,0
"""
with open("/tmp/customers.csv", "w") as f:
    f.write(csv_text)

The Easy Way — make_csv_dataset

It reads the header, guesses each column's type, picks out the label, batches and shuffles.

csv_ds = tf.data.experimental.make_csv_dataset(
    "/tmp/customers.csv", batch_size=3, label_name="bought",
    num_epochs=1, shuffle=False)

for features, label in csv_ds.take(1):
    for name, col in features.items():
        print(f"{name:7s} {col.dtype.name:7s} {col.numpy()}")
    print("label  ", label.numpy())
OUTPUT
age int32 [25 32 47] income int32 [32000 58000 91000] city string [b'Delhi' b'Pune' b'Baddi'] label [0 1 1]

The Manual Way — TextLineDataset + decode_csv

Useful when you want full control over column types and defaults for missing values.

defaults = [tf.constant(0.0), tf.constant(0.0), tf.constant(""), tf.constant(0)]   # one per column

def parse_line(line):
    age, income, city, bought = tf.io.decode_csv(line, record_defaults=defaults)
    x = tf.stack([age, income / 1000.0])          # numeric features
    return x, bought

lines = tf.data.TextLineDataset("/tmp/customers.csv").skip(1)   # skip the header
manual = lines.map(parse_line)
for x, y in manual.take(3):
    print(x.numpy(), y.numpy())
OUTPUT
[25. 32.] 0 [32. 58.] 1 [47. 91.] 1

Section 05

Try It — CSV Parser Playground

📄 Paste a CSV, See the Batches Interactive

Edit the CSV text. Pick the label column and batch size. The playground guesses column types the way make_csv_dataset does (int32 → float32 → string) and shows the first batches.

columnguessed dtypemissing valuesrole

Section 06

From Files and Folders

A very common layout stores one image per file, with the class as the folder name: data/cat/001.png. Let us make such a folder, then load it.

import os
for label in ["cat", "dog"]:
    os.makedirs(f"/tmp/pets/{label}", exist_ok=True)
    for i in range(3):
        img = tf.cast(tf.random.uniform([8, 8, 3], 0, 255, seed=i), tf.uint8)   # a tiny fake image
        tf.io.write_file(f"/tmp/pets/{label}/{i}.png", tf.io.encode_png(img))

class_names = tf.constant(["cat", "dog"])

def load(path):
    img = tf.io.decode_png(tf.io.read_file(path), channels=3)
    img = tf.image.convert_image_dtype(img, tf.float32)            # 0..1
    folder = tf.strings.split(path, os.sep)[-2]
    label = tf.argmax(tf.cast(folder == class_names, tf.int32))
    return img, label

files = tf.data.Dataset.list_files("/tmp/pets/*/*.png", shuffle=False)
images = files.map(load)
for img, lab in images.take(4):
    print(img.shape, img.dtype.name, "label", lab.numpy())
print("files found:", files.cardinality().numpy())
OUTPUT
(8, 8, 3) float32 label 0 (8, 8, 3) float32 label 0 (8, 8, 3) float32 label 0 (8, 8, 3) float32 label 1 files found: 6
💡
The Keras Shortcut

For image folders, tf.keras.utils.image_dataset_from_directory does all of this for you and returns a batched tf.data.Dataset. Doing it by hand once shows you what it does inside, and lets you handle unusual layouts.


Section 07

Which Source Should I Use?

Your dataStart withNotes
Arrays that fit in memoryfrom_tensor_slicesSimplest and fastest
A Python loop or custom readerfrom_generatorFlexible, but runs Python (slower)
CSV filesmake_csv_dataset or TextLineDatasetStreams from disk
Folders of images or textlist_files + mapOr the Keras directory helpers
Huge data, many files, cloud storageTFRecordDatasetLesson 3 of this module

Section 08

Golden Rules

🚚 Dataset Sources — Rules to Remember
1
from_tensor_slices cuts along axis 0. All parts of a tuple or dict must have the same first size.
2
from_tensors makes a single element. Use it only when you really want one.
3
Check ds.element_spec to see the shape and dtype of every element.
4
Read files lazily with TextLineDataset, list_files and map, so data can be bigger than memory.
5
Give CSV columns explicit defaults when values can be missing.