Mathew K Analytics

Lesson 49 · Data Science Projects

Deep Learning for Wine Type Classification: Step-by-Step Model Training Guide

In this lesson, you will learn to predict wine types using a deep learning approach. Knowing how to classify wines from their features is helpful for…

⬇ Download notebookOpen in Colab ↗

What you'll learn

Data

No separate download needed — the notebook creates or downloads everything it uses.

📓 Full notebook

Download .ipynb

Prediction of Wine Type using Deep Learning#

  • In this lesson, you will learn to predict wine types using a deep learning approach.

  • Knowing how to classify wines from their features is helpful for automating quality control and improving recommendations.

  • This hands-on notebook is great for beginners. You will see how a neural network works on a real dataset.

  • We will clean data, explore it visually, and build a deep learning model for classification.

  • No prior deep learning experience is required. Just follow along and type the code with me!

# Always suppress warnings for a cleaner output
import warnings
import numpy as np
np.random.seed(42)
warnings.filterwarnings("ignore")

Data setup#

  • We will use the classic Wine Dataset from the UCI repository.
  • Each row has measurements from a real wine.
  • The goal is to predict the wine type (Class 1, 2, or 3) from these features.
  • The dataset is small and perfect for learning deep learning basics.
# Download and load the classic wine classification dataset
import pandas as pd
url = 'https://archive.ics.uci.edu/ml/machine-learning-databases/wine/wine.data'
cols = ['Class','Alcohol','Malic_acid','Ash','Alcalinity_of_ash','Magnesium','Total_phenols','Flavanoids','Nonflavanoid_phenols','Proanthocyanins','Color_intensity','Hue','OD280_OD315','Proline']
df = pd.read_csv(url, header=None, names=cols)
print(df.shape)
print(df.head(3))
(178, 14)
   Class  Alcohol  Malic_acid   Ash  Alcalinity_of_ash  Magnesium  \
0      1    14.23        1.71  2.43               15.6        127   
1      1    13.20        1.78  2.14               11.2        100   
2      1    13.16        2.36  2.67               18.6        101   

   Total_phenols  Flavanoids  Nonflavanoid_phenols  Proanthocyanins  \
0           2.80        3.06                  0.28             2.29   
1           2.65        2.76                  0.26             1.28   
2           2.80        3.24                  0.30             2.81   

   Color_intensity   Hue  OD280_OD315  Proline  
0             5.64  1.04         3.92     1065  
1             4.38  1.05         3.40     1050  
2             5.68  1.03         3.17     1185  

Data Exploration#

  • Before training, let us explore what the data looks like.
  • We will look at summary statistics and see how many wines belong to each class.
  • Data exploration is important to understand patterns and possible issues.
# Show statistics and distribution of classes
print(df.describe())
print("\nWine type counts:")
print(df['Class'].value_counts())
            Class     Alcohol  Malic_acid         Ash  Alcalinity_of_ash  \
count  178.000000  178.000000  178.000000  178.000000         178.000000   
mean     1.938202   13.000618    2.336348    2.366517          19.494944   
std      0.775035    0.811827    1.117146    0.274344           3.339564   
min      1.000000   11.030000    0.740000    1.360000          10.600000   
25%      1.000000   12.362500    1.602500    2.210000          17.200000   
50%      2.000000   13.050000    1.865000    2.360000          19.500000   
75%      3.000000   13.677500    3.082500    2.557500          21.500000   
max      3.000000   14.830000    5.800000    3.230000          30.000000   

        Magnesium  Total_phenols  Flavanoids  Nonflavanoid_phenols  \
count  178.000000     178.000000  178.000000            178.000000   
mean    99.741573       2.295112    2.029270              0.361854   
std     14.282484       0.625851    0.998859              0.124453   
min     70.000000       0.980000    0.340000              0.130000   
25%     88.000000       1.742500    1.205000              0.270000   
50%     98.000000       2.355000    2.135000              0.340000   
75%    107.000000       2.800000    2.875000              0.437500   
max    162.000000       3.880000    5.080000              0.660000   

       Proanthocyanins  Color_intensity         Hue  OD280_OD315      Proline  
count       178.000000       178.000000  178.000000   178.000000   178.000000  
mean          1.590899         5.058090    0.957449     2.611685   746.893258  
std           0.572359         2.318286    0.228572     0.709990   314.907474  
min           0.410000         1.280000    0.480000     1.270000   278.000000  
25%           1.250000         3.220000    0.782500     1.937500   500.500000  
50%           1.555000         4.690000    0.965000     2.780000   673.500000  
75%           1.950000         6.200000    1.120000     3.170000   985.000000  
max           3.580000        13.000000    1.710000     4.000000  1680.000000  

Wine type counts:
Class
2    71
1    59
3    48
Name: count, dtype: int64
# Show correlation matrix to check feature relationships
corr = df.corr()
print(corr['Class'].sort_values(ascending=False))
Class                   1.000000
Alcalinity_of_ash       0.517859
Nonflavanoid_phenols    0.489109
Malic_acid              0.437776
Color_intensity         0.265668
Ash                    -0.049643
Magnesium              -0.209179
Alcohol                -0.328222
Proanthocyanins        -0.499130
Hue                    -0.617369
Proline                -0.633717
Total_phenols          -0.719163
OD280_OD315            -0.788230
Flavanoids             -0.847498
Name: Class, dtype: float64
# Visualize feature distributions for two classes
import seaborn as sns
import matplotlib.pyplot as plt
sns.histplot(df, x='Alcohol', hue='Class', bins=20, element='step')
plt.title('Alcohol content by wine type')
plt.show()
No description has been provided for this image

Data Preprocessing#

  • Machine learning models work best when data is numeric and scaled properly.
  • We will prepare the labels and scale the feature values to a similar range.
  • This step is important for deep learning models to train correctly.
# Split data into features and labels, then scale features
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler

X = df.drop('Class', axis=1).values
y = df['Class'].values - 1  # classes 0,1,2

scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
# Split into train and test sets
X_train, X_test, y_train, y_test = train_test_split(X_scaled, y, test_size=0.2, random_state=42)
print(X_train.shape, X_test.shape)
(142, 13) (36, 13)

Introduction to Deep Learning Models#

  • Deep learning is a special type of machine learning that uses neural networks.
  • Neural networks try to learn complex patterns automatically instead of us writing rules.
  • They contain layers of simple objects called neurons, connected like the brain.
  • They perform extremely well when given enough data and the right settings.
# Build a simple neural network with Keras
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers

model = keras.Sequential([
    layers.Dense(32, activation='relu', input_shape=(X_train.shape[1],)),
    layers.Dense(16, activation='relu'),
    layers.Dense(3, activation='softmax')  # Output for 3 wine types
])
# Show model structure
model.summary()
Model: "sequential"
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓
┃ Layer (type)                    ┃ Output Shape           ┃       Param # ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩
│ dense (Dense)                   │ (None, 32)             │           448 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ dense_1 (Dense)                 │ (None, 16)             │           528 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ dense_2 (Dense)                 │ (None, 3)              │            51 │
└─────────────────────────────────┴────────────────────────┴───────────────┘
 Total params: 1,027 (4.01 KB)
 Trainable params: 1,027 (4.01 KB)
 Non-trainable params: 0 (0.00 B)
# Compile the model to set up for training
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
# Train the neural network
history = model.fit(X_train, y_train, epochs=50, batch_size=16, validation_split=0.1, verbose=1)
Epoch 1/50
8/8 ━━━━━━━━━━━━━━━━━━━━ 1s 29ms/step - accuracy: 0.1417 - loss: 1.2740 - val_accuracy: 0.0667 - val_loss: 1.2798
Epoch 2/50
8/8 ━━━━━━━━━━━━━━━━━━━━ 0s 15ms/step - accuracy: 0.3150 - loss: 1.1434 - val_accuracy: 0.2000 - val_loss: 1.0976
Epoch 3/50
8/8 ━━━━━━━━━━━━━━━━━━━━ 0s 12ms/step - accuracy: 0.4646 - loss: 1.0303 - val_accuracy: 0.6000 - val_loss: 0.9419
Epoch 4/50
8/8 ━━━━━━━━━━━━━━━━━━━━ 0s 14ms/step - accuracy: 0.6772 - loss: 0.9277 - val_accuracy: 0.7333 - val_loss: 0.8243
Epoch 5/50
8/8 ━━━━━━━━━━━━━━━━━━━━ 0s 13ms/step - accuracy: 0.8661 - loss: 0.8357 - val_accuracy: 0.8000 - val_loss: 0.7175
Epoch 6/50
8/8 ━━━━━━━━━━━━━━━━━━━━ 0s 11ms/step - accuracy: 0.9528 - loss: 0.7477 - val_accuracy: 0.8667 - val_loss: 0.6266
Epoch 7/50
8/8 ━━━━━━━━━━━━━━━━━━━━ 0s 13ms/step - accuracy: 0.9528 - loss: 0.6703 - val_accuracy: 0.9333 - val_loss: 0.5378
Epoch 8/50
8/8 ━━━━━━━━━━━━━━━━━━━━ 0s 13ms/step - accuracy: 0.9606 - loss: 0.5903 - val_accuracy: 1.0000 - val_loss: 0.4721
Epoch 9/50
8/8 ━━━━━━━━━━━━━━━━━━━━ 0s 10ms/step - accuracy: 0.9685 - loss: 0.5198 - val_accuracy: 1.0000 - val_loss: 0.4033
Epoch 10/50
8/8 ━━━━━━━━━━━━━━━━━━━━ 0s 14ms/step - accuracy: 0.9685 - loss: 0.4537 - val_accuracy: 1.0000 - val_loss: 0.3514
Epoch 11/50
8/8 ━━━━━━━━━━━━━━━━━━━━ 0s 9ms/step - accuracy: 0.9685 - loss: 0.3943 - val_accuracy: 1.0000 - val_loss: 0.3069
Epoch 12/50
8/8 ━━━━━━━━━━━━━━━━━━━━ 0s 13ms/step - accuracy: 0.9764 - loss: 0.3427 - val_accuracy: 1.0000 - val_loss: 0.2768
Epoch 13/50
8/8 ━━━━━━━━━━━━━━━━━━━━ 0s 11ms/step - accuracy: 0.9843 - loss: 0.2985 - val_accuracy: 1.0000 - val_loss: 0.2484
Epoch 14/50
8/8 ━━━━━━━━━━━━━━━━━━━━ 0s 14ms/step - accuracy: 0.9843 - loss: 0.2598 - val_accuracy: 1.0000 - val_loss: 0.2244
Epoch 15/50
8/8 ━━━━━━━━━━━━━━━━━━━━ 0s 14ms/step - accuracy: 0.9843 - loss: 0.2274 - val_accuracy: 1.0000 - val_loss: 0.2084
Epoch 16/50
8/8 ━━━━━━━━━━━━━━━━━━━━ 0s 12ms/step - accuracy: 0.9843 - loss: 0.1991 - val_accuracy: 1.0000 - val_loss: 0.1924
Epoch 17/50
8/8 ━━━━━━━━━━━━━━━━━━━━ 0s 12ms/step - accuracy: 0.9843 - loss: 0.1760 - val_accuracy: 1.0000 - val_loss: 0.1793
Epoch 18/50
8/8 ━━━━━━━━━━━━━━━━━━━━ 0s 11ms/step - accuracy: 0.9843 - loss: 0.1569 - val_accuracy: 1.0000 - val_loss: 0.1699
Epoch 19/50
8/8 ━━━━━━━━━━━━━━━━━━━━ 0s 12ms/step - accuracy: 0.9843 - loss: 0.1396 - val_accuracy: 1.0000 - val_loss: 0.1575
Epoch 20/50
8/8 ━━━━━━━━━━━━━━━━━━━━ 0s 13ms/step - accuracy: 0.9921 - loss: 0.1258 - val_accuracy: 1.0000 - val_loss: 0.1476
Epoch 21/50
8/8 ━━━━━━━━━━━━━━━━━━━━ 0s 13ms/step - accuracy: 0.9921 - loss: 0.1131 - val_accuracy: 1.0000 - val_loss: 0.1338
Epoch 22/50
8/8 ━━━━━━━━━━━━━━━━━━━━ 0s 10ms/step - accuracy: 0.9921 - loss: 0.1028 - val_accuracy: 1.0000 - val_loss: 0.1251
Epoch 23/50
8/8 ━━━━━━━━━━━━━━━━━━━━ 0s 11ms/step - accuracy: 0.9921 - loss: 0.0937 - val_accuracy: 1.0000 - val_loss: 0.1177
Epoch 24/50
8/8 ━━━━━━━━━━━━━━━━━━━━ 0s 13ms/step - accuracy: 0.9921 - loss: 0.0855 - val_accuracy: 1.0000 - val_loss: 0.1129
Epoch 25/50
8/8 ━━━━━━━━━━━━━━━━━━━━ 0s 13ms/step - accuracy: 0.9921 - loss: 0.0784 - val_accuracy: 1.0000 - val_loss: 0.1054
Epoch 26/50
8/8 ━━━━━━━━━━━━━━━━━━━━ 0s 13ms/step - accuracy: 0.9921 - loss: 0.0725 - val_accuracy: 1.0000 - val_loss: 0.1013
Epoch 27/50
8/8 ━━━━━━━━━━━━━━━━━━━━ 0s 13ms/step - accuracy: 0.9921 - loss: 0.0669 - val_accuracy: 1.0000 - val_loss: 0.1000
Epoch 28/50
8/8 ━━━━━━━━━━━━━━━━━━━━ 0s 16ms/step - accuracy: 0.9921 - loss: 0.0623 - val_accuracy: 1.0000 - val_loss: 0.0975
Epoch 29/50
8/8 ━━━━━━━━━━━━━━━━━━━━ 0s 12ms/step - accuracy: 0.9921 - loss: 0.0576 - val_accuracy: 1.0000 - val_loss: 0.0929
Epoch 30/50
8/8 ━━━━━━━━━━━━━━━━━━━━ 0s 11ms/step - accuracy: 0.9921 - loss: 0.0538 - val_accuracy: 1.0000 - val_loss: 0.0900
Epoch 31/50
8/8 ━━━━━━━━━━━━━━━━━━━━ 0s 12ms/step - accuracy: 1.0000 - loss: 0.0499 - val_accuracy: 1.0000 - val_loss: 0.0853
Epoch 32/50
8/8 ━━━━━━━━━━━━━━━━━━━━ 0s 12ms/step - accuracy: 1.0000 - loss: 0.0469 - val_accuracy: 1.0000 - val_loss: 0.0835
Epoch 33/50
8/8 ━━━━━━━━━━━━━━━━━━━━ 0s 11ms/step - accuracy: 1.0000 - loss: 0.0437 - val_accuracy: 1.0000 - val_loss: 0.0808
Epoch 34/50
8/8 ━━━━━━━━━━━━━━━━━━━━ 0s 12ms/step - accuracy: 1.0000 - loss: 0.0411 - val_accuracy: 1.0000 - val_loss: 0.0800
Epoch 35/50
8/8 ━━━━━━━━━━━━━━━━━━━━ 0s 9ms/step - accuracy: 1.0000 - loss: 0.0384 - val_accuracy: 1.0000 - val_loss: 0.0755
Epoch 36/50
8/8 ━━━━━━━━━━━━━━━━━━━━ 0s 12ms/step - accuracy: 1.0000 - loss: 0.0361 - val_accuracy: 1.0000 - val_loss: 0.0724
Epoch 37/50
8/8 ━━━━━━━━━━━━━━━━━━━━ 0s 12ms/step - accuracy: 1.0000 - loss: 0.0340 - val_accuracy: 1.0000 - val_loss: 0.0693
Epoch 38/50
8/8 ━━━━━━━━━━━━━━━━━━━━ 0s 12ms/step - accuracy: 1.0000 - loss: 0.0323 - val_accuracy: 1.0000 - val_loss: 0.0668
Epoch 39/50
8/8 ━━━━━━━━━━━━━━━━━━━━ 0s 12ms/step - accuracy: 1.0000 - loss: 0.0304 - val_accuracy: 1.0000 - val_loss: 0.0673
Epoch 40/50
8/8 ━━━━━━━━━━━━━━━━━━━━ 0s 11ms/step - accuracy: 1.0000 - loss: 0.0286 - val_accuracy: 1.0000 - val_loss: 0.0647
Epoch 41/50
8/8 ━━━━━━━━━━━━━━━━━━━━ 0s 13ms/step - accuracy: 1.0000 - loss: 0.0273 - val_accuracy: 1.0000 - val_loss: 0.0627
Epoch 42/50
8/8 ━━━━━━━━━━━━━━━━━━━━ 0s 13ms/step - accuracy: 1.0000 - loss: 0.0258 - val_accuracy: 1.0000 - val_loss: 0.0627
Epoch 43/50
8/8 ━━━━━━━━━━━━━━━━━━━━ 0s 12ms/step - accuracy: 1.0000 - loss: 0.0246 - val_accuracy: 1.0000 - val_loss: 0.0601
Epoch 44/50
8/8 ━━━━━━━━━━━━━━━━━━━━ 0s 13ms/step - accuracy: 1.0000 - loss: 0.0232 - val_accuracy: 1.0000 - val_loss: 0.0573
Epoch 45/50
8/8 ━━━━━━━━━━━━━━━━━━━━ 0s 13ms/step - accuracy: 1.0000 - loss: 0.0222 - val_accuracy: 1.0000 - val_loss: 0.0547
Epoch 46/50
8/8 ━━━━━━━━━━━━━━━━━━━━ 0s 13ms/step - accuracy: 1.0000 - loss: 0.0211 - val_accuracy: 1.0000 - val_loss: 0.0554
Epoch 47/50
8/8 ━━━━━━━━━━━━━━━━━━━━ 0s 11ms/step - accuracy: 1.0000 - loss: 0.0201 - val_accuracy: 1.0000 - val_loss: 0.0556
Epoch 48/50
8/8 ━━━━━━━━━━━━━━━━━━━━ 0s 12ms/step - accuracy: 1.0000 - loss: 0.0191 - val_accuracy: 1.0000 - val_loss: 0.0534
Epoch 49/50
8/8 ━━━━━━━━━━━━━━━━━━━━ 0s 14ms/step - accuracy: 1.0000 - loss: 0.0182 - val_accuracy: 1.0000 - val_loss: 0.0517
Epoch 50/50
8/8 ━━━━━━━━━━━━━━━━━━━━ 0s 12ms/step - accuracy: 1.0000 - loss: 0.0175 - val_accuracy: 1.0000 - val_loss: 0.0507
# Plot training and validation accuracy over time
plt.plot(history.history['accuracy'], label='Train accuracy')
plt.plot(history.history['val_accuracy'], label='Validation accuracy')
plt.xlabel('Epoch')
plt.ylabel('Accuracy')
plt.title('Training progress')
plt.legend()
plt.show()
No description has been provided for this image
# Evaluate the model on test data
test_loss, test_acc = model.evaluate(X_test, y_test, verbose=0)
print(f"Test accuracy: {test_acc:.2f}")
Test accuracy: 1.00

Making Predictions#

  • Let us try using our trained neural network to predict the class of a new wine.
  • You will enter feature values, and the model will output the predicted wine type.
  • This is what makes deep learning models useful for real world decision making.
# Get user input and predict wine class
import numpy as np
features = []
feature_names = list(df.columns[1:])
for f in feature_names:
    val = float(input(f'Enter value for {f}: '))
    features.append(val)
user_input = scaler.transform([features])
probs = model.predict(user_input)
pred_class = np.argmax(probs) + 1
print(f'Predicted wine class: {pred_class}')
1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 81ms/step
Predicted wine class: 1
# Confusion matrix for detailed accuracy
from sklearn.metrics import confusion_matrix
y_pred = np.argmax(model.predict(X_test), axis=1)
cm = confusion_matrix(y_test, y_pred)
print(cm)
2/2 ━━━━━━━━━━━━━━━━━━━━ 0s 14ms/step
[[14  0  0]
 [ 0 14  0]
 [ 0  0  8]]
# Try a mini project: Tune the model and see what happens
# Change epochs, batch size, or hidden sizes and retrain.
# For example, try increasing the first dense layer size to 64, or use 100 epochs.

# Rebuild and retrain if you want to practice more!

Next Steps & Stay Tuned!#

  • Congratulations, you have just built your first deep learning classifier on real data!
  • Practice by changing the model or trying other datasets listed in this channel.
  • Make sure you subscribe and like the video for more deep learning lessons.
  • Let me know in the comments what topics you want next!

Found this useful?

All lessons, notebooks and datasets here are free. If they helped you, a coffee keeps new lessons coming.