Building and training a neural network for handwritten digit recognition
In this example we will consider data processing and training of a neural network model for image classification. The MNIST dataset, which contains 70000 labelled images of handwritten digits, is chosen as a set of observation objects. The example will use a .csv file in which the images are expanded as tabular data containing brightness values for each pixel.
Connection of libraries for data processing:
In [ ]:
Pkg.add(["Colors", "CSV", "Flux"])
In [ ]:
using CSV, DataFrames
Loading data into a variable:
In [ ]:
df = DataFrame(CSV.File("$(@__DIR__)/mnist_784.csv"));
Conclusion the first five lines of the dataframe:
In [ ]:
first(df,5)
Out[0]:
Conclusion the first five rows and the last column of the dataframe, which tells you what class the object of observation belongs to:
In [ ]:
df[1:5,780:785]
Out[0]:
Dividing the data set into training and test samples at a ratio of 8 to 2:
In [ ]:
X_train, y_train = Matrix(df[1:56000,1:784]), df[1:56000,785]
X_test, y__test = Matrix(df[56001:end,1:784]), df[56001:end,785]
Out[0]:
Conversion of samples into formats acceptable for neural network processing:
In [ ]:
X_train, X_test = convert(Matrix{Float32}, X_train), convert(Matrix{Float32}, X_test)
y_train, y__test = convert(Vector{Float32}, y_train), convert(Vector{Float32}, y__test)
Out[0]:
Connecting a library for data visualisation:
In [ ]:
using Plots
Displaying an object and its class:
In [ ]:
test_img = Vector(df[60000,1:784])
test_img = (reshape(test_img, 28, 28)) / 256
using Colors
println("Класс объекта: ", df[60000,785])
plot(Gray.(test_img))
Out[0]:
Final data transformation for neural network processing:
In [ ]:
X_train, X_test = X_train', X_test'
y_train, y__test = y_train', y__test'
Out[0]:
Connecting a machine learning library:
In [ ]:
using Flux
using Flux: train!
Defining the structure of a neural network:
In [ ]:
model = Chain(
Dense(784, 15,elu),
Dense(15, 10,sigmoid),
softmax
)
Out[0]:
Test result of recognition (before training the model):
In [ ]:
predict = model(X_test)
Out[0]:
Determination of training parameters:
In [ ]:
loss(x, y) = Flux.mse(model(x), reshape(Flux.onehotbatch(y_train,0:9), 10, 56000)) # функция потерь
ps = Flux.params(model) # указание на параметры корректируемые в процессе обучения
opt = Adam(0.01) # выбор оптимизатора
Out[0]:
Defining a function to calculate the accuracy of the model:
In [ ]:
function accuracy()
correct = 0
for index in 1:length(y__test)
probs = model(Flux.unsqueeze(X_test[:,index],dims=3))
predicted_digit = argmax(probs)[1]-1
if predicted_digit == y__test'[index]
correct +=1
end
end
return correct/length(y__test')
end
Out[0]:
Iterative model training process:
In [ ]:
loss_history = [] # определение пустого массива для записи функции потерь
epochs = 50 # определение количества шагов обучения модели
for epoch in 1:epochs # повторение обучения модели на каждом шаге
train!(loss, ps, [(X_train, y_train)], opt) # обучающая функция, корректирующая параметры модели
train_loss = loss(X_train, y_train) # расчёт функции потерь на текущем шаге
push!(loss_history, train_loss) # запись функции потерь
acc = accuracy() * 100
if epoch == 1 # условие для отображения функции потерь на каждом шаге обучения
println("Epoch = $epoch : Training Loss = $train_loss, Model Accuracy = $acc %");
elseif epoch % 1 == 0
println("Epoch = $epoch : Training Loss = $train_loss, Model Accuracy = $acc %");
end
end
Visualisation of the change in the loss function at each training step:
In [ ]:
plot((1:epochs), loss_history, title="Изменение функции потерь", xlabel="Шаг обучения", ylabel="Функция потерь")
Out[0]:
Displaying results:
In [ ]:
number = 13000
test_img = Vector(df[56000+number,1:784])
test_img = (reshape(test_img, 28, 28)) / 256
using Colors
result = model(X_test[:,number])
println("Известный класс объекта: ", df[56000+number,785], "\n ", "Вектор, характеризующий класс объекта: ", result)
plot(Gray.(test_img))
Out[0]:
Conclusion
In this example, the pixel brightness data was preprocessed and the neural network architecture, optimiser parameters and loss function were defined.
The model was trained and showed reasonably accurate, but not perfect class partitioning. To improve the recognition quality, the neural network can be modified by changing the architecture of layers and increasing the training sample.