Introduction
The error Unable to build Dense layer with non-floating point dtype occurs when you pass integer or string tensors to a Dense layer. Dense layers perform matrix multiplication and need floating-point inputs because the weights and gradients are floats. The fix is to cast your input data to float32 before it reaches the Dense layer — either in your preprocessing pipeline, with a tf.keras.layers.Rescaling layer, or with tf.cast().
The Error
1import tensorflow as tf
2
3# Integer input triggers the error
4model = tf.keras.Sequential([
5 tf.keras.layers.Dense(64, input_shape=(10,), dtype='int32')
6])
7# TypeError: Unable to build Dense layer with non-floating point dtype int32
Or at training time:
1model = tf.keras.Sequential([
2 tf.keras.layers.Dense(64, input_shape=(10,))
3])
4
5X = tf.constant([[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]]) # int32 by default
6model(X)
7# TypeError: Cannot convert a value of dtype int32 to float32
Why Dense Requires Floats
Dense computes output = activation(input @ kernel + bias):
kernel (weights) is float32
bias is float32
Matrix multiplication requires matching types
Backpropagation computes gradients, which must be continuous (floats)
Integer math has no gradients — you cannot compute d(loss)/d(weight) with integers.
1import tensorflow as tf
2import numpy as np
3
4# Integer data
5X_train = np.array([[1, 2, 3], [4, 5, 6]], dtype=np.int32)
6y_train = np.array([0, 1])
7
8# Cast to float32
9X_train = X_train.astype(np.float32)
10
11model = tf.keras.Sequential([
12 tf.keras.layers.Dense(64, activation='relu', input_shape=(3,)),
13 tf.keras.layers.Dense(1, activation='sigmoid')
14])
15
16model.compile(optimizer='adam', loss='binary_crossentropy')
17model.fit(X_train, y_train, epochs=5)
Fix 2: Cast in the Model with a Lambda Layer
1model = tf.keras.Sequential([
2 tf.keras.layers.Lambda(lambda x: tf.cast(x, tf.float32)),
3 tf.keras.layers.Dense(64, activation='relu'),
4 tf.keras.layers.Dense(1)
5])
6
7# Now integer inputs work
8X = tf.constant([[1, 2, 3]], dtype=tf.int32)
9model(X) # No error
Fix 3: Cast in tf.data Pipeline
1def preprocess(features, label):
2 features = tf.cast(features, tf.float32)
3 return features, label
4
5dataset = tf.data.Dataset.from_tensor_slices((X_int, y))
6dataset = dataset.map(preprocess).batch(32)
7
8model.fit(dataset, epochs=10)
Fix 4: Rescaling Layer for Image Data
1# Image pixels are uint8 (0-255)
2model = tf.keras.Sequential([
3 tf.keras.layers.Rescaling(1./255, input_shape=(28, 28, 1)),
4 # Rescaling converts uint8 to float32 and scales to [0, 1]
5 tf.keras.layers.Flatten(),
6 tf.keras.layers.Dense(128, activation='relu'),
7 tf.keras.layers.Dense(10, activation='softmax')
8])
9
10# uint8 images work directly
11images = tf.random.uniform((32, 28, 28, 1), 0, 255, dtype=tf.int32)
12images = tf.cast(images, tf.uint8)
13model(images) # Rescaling handles the conversion
Fix 5: Feature Columns with Integer Features
1# When using feature columns with integer data
2feature_columns = [
3 tf.feature_column.numeric_column('age', dtype=tf.float32),
4 tf.feature_column.numeric_column('income', dtype=tf.float32),
5]
6
7# DenseFeatures layer converts to float automatically
8model = tf.keras.Sequential([
9 tf.keras.layers.DenseFeatures(feature_columns),
10 tf.keras.layers.Dense(64, activation='relu'),
11 tf.keras.layers.Dense(1)
12])
Checking and Converting Dtypes
1import tensorflow as tf
2
3# Check tensor dtype
4x = tf.constant([1, 2, 3])
5print(x.dtype) # tf.int32
6
7# Convert
8x_float = tf.cast(x, tf.float32)
9print(x_float.dtype) # tf.float32
10
11# Check NumPy array dtype
12import numpy as np
13arr = np.array([1, 2, 3])
14print(arr.dtype) # int64
15
16arr_float = arr.astype(np.float32)
17print(arr_float.dtype) # float32
18
19# Check DataFrame dtypes
20import pandas as pd
21df = pd.DataFrame({'a': [1, 2], 'b': [3, 4]})
22print(df.dtypes) # int64 for both
23X = df.values.astype(np.float32)
Using float16 or float64
1# float16 (half precision) — faster on GPUs with tensor cores
2model = tf.keras.Sequential([
3 tf.keras.layers.Dense(64, activation='relu', dtype='float16'),
4 tf.keras.layers.Dense(1, dtype='float16')
5])
6
7# Mixed precision — recommended for GPU training
8tf.keras.mixed_precision.set_global_policy('mixed_float16')
9model = tf.keras.Sequential([
10 tf.keras.layers.Dense(64, activation='relu'), # Uses float16 compute, float32 variables
11 tf.keras.layers.Dense(1)
12])
13
14# float64 — rarely needed, slower
15model = tf.keras.Sequential([
16 tf.keras.layers.Dense(64, dtype='float64'),
17])
Common Pitfalls
Pandas DataFrames with mixed types: If a DataFrame column has strings or None values, df.values may be object dtype. Use df.select_dtypes(include=[np.number]).values.astype(np.float32) to get only numeric columns.
One-hot encoded labels as integers: Labels for sparse_categorical_crossentropy should be integers, but features must be floats. Do not cast labels to float — cast only the input features.
Image data as uint8: Raw image data is uint8 (0-255). Add Rescaling(1./255) as the first layer, or convert in preprocessing: images = images.astype('float32') / 255.0.
Embedding layers vs Dense: Embedding layers accept integer inputs (token IDs). Only Dense layers require floats. Do not cast embedding inputs to float.
tf.data type inference: tf.data.Dataset.from_tensor_slices(np_array) preserves the NumPy dtype. An int64 array creates an int64 dataset. Add .map(lambda x, y: (tf.cast(x, tf.float32), y)) to convert.
Summary
Dense layers require floating-point input — integer and string dtypes are rejected
Cast input data with X.astype(np.float32) or tf.cast(x, tf.float32)
Use Rescaling(1./255) for uint8 image data
Add a Lambda(lambda x: tf.cast(x, tf.float32)) layer to handle integer inputs in the model
Cast in the tf.data pipeline with .map() for clean data processing
Embedding layers accept integers — only Dense and other computation layers need floats