Ces dernières années, le domaine de l'intelligence artificielle a fait des progrès remarquables. Un algorithme appelé réseau de neurones est généralement utilisé pour reconnaître et juger les choses par l'intelligence artificielle. Il s'agit d'une tentative d'imiter le fonctionnement du cerveau humain, car il apprend automatiquement d'une approche d'ingénierie. Cette fois, dans le cadre de cela, laissez l'ordinateur reconnaître les chiffres manuscrits afin que les humains puissent les reconnaître naturellement.
Un réseau neuronal est un modèle d'apprentissage qui imite le nerf cérébral humain. En effectuant un grand nombre de transformations non linéaires, c'est un substitut qui peut produire des résultats très complexes à partir de données données. Dans le domaine de la reconnaissance d'image, on peut dire que la reconnaissance d'image est réalisée en appliquant un processus de corrélation appelé template matching au réseau neuronal. (Bien qu'il puisse y avoir des malentendus, il ne s'agit que d'un processus de corrélation en termes de convolution à partir de pixels et de luminosité.)
L'image à reconnaître cette fois est un numéro manuscrit de MNIST.
Téléchargeons. Comme ce ne sont pas des données d'image qui peuvent être utilisées telles quelles après le téléchargement Convertissons-les en données d'image en se référant aux documents suivants sur le site officiel.
TRAINING SET LABEL FILE (train-labels-idx1-ubyte):
[offset] [type] [value] [description] 0000 32 bit integer 0x00000801(2049) magic number (MSB first) 0004 32 bit integer 60000 number of items 0008 unsigned byte ?? label 0009 unsigned byte ?? label ........ xxxx unsigned byte ?? label The labels values are 0 to 9.
TRAINING SET IMAGE FILE (train-images-idx3-ubyte):
[offset] [type] [value] [description] 0000 32 bit integer 0x00000803(2051) magic number 0004 32 bit integer 60000 number of images 0008 32 bit integer 28 number of rows 0012 32 bit integer 28 number of columns 0016 unsigned byte ?? pixel 0017 unsigned byte ?? pixel ........ xxxx unsigned byte ?? pixel Pixels are organized row-wise. Pixel values are 0 to 255. 0 means background (white), 255 means foreground (black).
Vous pouvez voir que le signal de l'enseignant est stocké après l'offset 8 et les données d'apprentissage sont stockées après l'offset 16. Par conséquent, si vous l'ouvrez en tant que fichier binaire et extrayez la chaîne d'octets pour chaque valeur de pixel (28 * 28), vous pouvez obtenir le fichier image. Si vous effectuez la binarisation de manière appropriée, vous pouvez obtenir les données d'image suivantes de nombres manuscrits pour 60000 données. Nous utiliserons ces données de test supplémentaires dans la formation du réseau neuronal.
Le modèle du réseau neuronal utilisé cette fois est défini par les exigences suivantes.
--Une couche d'entrée, deux couches cachées, une couche de sortie --Toutes les fonctions d'activation sont sigmoïdes
C'est un réseau simple et extrêmement neuronal, mais est-ce le fait qu'il utilise deux couches cachées? Il y a beaucoup de choses à améliorer, mais pour l'instant, mettons cela en pratique.
L'implémentation du code est illustrée ci-dessous.
MultiLayerPerceptron_MNIST.py
# 1. Preprocess
import random
# 1.1. Make NeuralLetwork
# 1.1.1. Define Layers
n_hidden = 2
n_layer = n_hidden + 2
# 1.1.2. Define Units
n_unit_i = 7 * 7 + 1
n_unit_h = 20 # all
n_unit_o = 10
unit_i = [0 for u in range(n_unit_i)]
unit_h1 = [0 for u in range(n_unit_h)]
unit_h2 = [0 for u in range(n_unit_h)]
unit_o = [0 for u in range(n_unit_o)]
# 1.1.3. Initialize weight
w1 = [[random.uniform(-1, 1) for u_before in range(n_unit_i)] for u_after in range(n_unit_h)]
w2 = [[random.uniform(-1, 1) for u_before in range(n_unit_h)] for u_after in range(n_unit_h)]
w3 = [[random.uniform(-1, 1) for u_before in range(n_unit_h)] for u_after in range(n_unit_o)]
# 1.2. Define dataset
import mydatasets
n_data = 100
ipt = mydatasets.inputdata("digit")
res = ipt.load_data2(size=(7, 7), num=n_data)
train = res[0][0]
for k in train:
for n in k:
n.insert(0, 1)
def maketeach(kind):
buf = []
for o in range(n_unit_o):
if o == kind:
buf.append(1)
else:
buf.append(0)
return buf
# 1.3 Implement forward propagation
import math
# 1.3.1 Define activation fucntion
def sigmoid(z):
if z > 10: return 0.99999
elif z < -10: return 0.00001
else: return 1 / (1 + math.exp(-1 * z))
# 1.3.2 forward propagation
def forward(train_vec):
for i in range(n_unit_i):
unit_i[i] = train_vec[i]
unit_i[0] = 1
# 1.3.2.1 forward between input-hidden1
for h1 in range(n_unit_h):
buf = 0
for i in range(n_unit_i):
buf += unit_i[i] * w1[h1][i]
unit_h1[h1] = sigmoid(buf)
unit_h1[0] = 1
# 1.3.2.2 forward between hidden1-hidden2
for h2 in range(n_unit_h):
buf = 0
for h1 in range(n_unit_h):
buf += unit_h1[h1] * w2[h2][h1]
unit_h2[h2] = sigmoid(buf)
unit_h2[0] = 1
# 1.3.2.3 forward between hidden2-output
for o in range(n_unit_o):
buf = 0
for h2 in range(n_unit_h):
buf += unit_h2[h2] * w3[o][h2]
unit_o[o] = sigmoid(buf)
# 1.3.3 back propagation
alpha = 0.1
def backpropagation(teach_vec):
# 1.3.3.1 get cost
buf = 0
for o in range(n_unit_o):
buf += (teach_vec[o] - unit_o[o]) ** 2
cost = buf / 2
# 1.3.3.2 get grad between hidden2-output
for o in range(n_unit_o):
for h2 in range(n_unit_h):
delta = (unit_o[o] - teach_vec[o]) * unit_o[o] * (1 - unit_o[o]) * unit_h2[h2]
w3[o][h2] -= alpha * delta
# 1.3.3.3 get grad
for o in range(n_unit_o):
for h2 in range(n_unit_h):
for h1 in range(n_unit_h):
delta = ((unit_o[o] - teach_vec[o]) * unit_o[o] * (1 - unit_o[o])
* w3[o][h2] * unit_h2[h2] * (1 - unit_h2[h2]) * unit_h1[h1])
w2[h2][h1] -= alpha * delta
# 1.3.3.4 get grad
for o in range(n_unit_o):
for h2 in range(n_unit_h):
for h1 in range(n_unit_h):
for i in range(n_unit_i):
delta = ((unit_o[o] - teach_vec[o]) * unit_o[o] * (1 - unit_o[o])
* w3[o][h2] * unit_h2[h2] * (1 - unit_h2[h2])
* w2[h2][h1] * unit_h1[h1] * (1 -unit_h1[h1]) * unit_i[i])
w1[h1][i] -= alpha *delta
return cost
import matplotlib.pyplot as plt
plt_x = []
plt_y = []
n_epoch = 30
n_train = len(train)
n_kind = 10
n = 0
error_threshold = 0.001
print("Backpropagation training is started now.")
def training(n):
for e in range(n_epoch):
for d in range(n_data):
for k in range(n_kind):
try:
n += 1
forward(train[k][d])
c = backpropagation(maketeach(k))
plt_x.append(n)
plt_y.append(c)
if n % 100 == 0:
print("learn num: {0}".format(n))
if c < error_threshold and e > n_epoch // 2:
print("cost is least than error threshold. (n: {})".format(n))
return 1
except Exception as e:
print("n:{}, d:{}, k{}, Error:{}".format(n, d, k, e.args))
pass
return 0
def forecast(train_data, dim):
forward(train_data)
res = unit_o
n = 0
for r in res:
if r == max(res):
max_score = n
n += 1
print("max score : {}".format(max_score))
print("scores is below : ")
print(res)
import numpy as np
import cv2
mat = []
row = []
cnt = 0
n = 0
for t in range(1, len(train_data)):
row.append(train_data[t])
cnt += 1
n += 1
if cnt == 7:
#print("if statement is called at n:{}".format(n))
mat.append(row)
row = []
cnt = 0
cv2.imwrite('forecast_input.png', np.array(mat)*255)
return max_score
def validation(vaild_sets):
n_dim = 7
correct = 0
incorrect = 0
n_kind = 10
for d in range(n_data):
for k in range(n_kind):
if forecast(train[k][d], n_dim) == k:
correct += 1
else:
incorrect += 1
total = correct + incorrect
print("validation result:: correct answer is {} / {}".format(correct, total))
training(n)
plt.plot(plt_x, plt_y)
plt.xlim(0, 30000)
plt.ylim(0.0, 1.51)
plt.show()
valid = res[1][0]
for k in valid:
for n in k:
n.insert(0, 1)
validation(valid)
En prenant le nombre de graphiques d'erreur d'apprentissage, les résultats suivants ont été obtenus.
Au début, le réseau neuronal ne peut pas faire la distinction entre 0 (bonne réponse) et 1 (mauvaise réponse), et fait un jugement semi-fini de 0,5. Au fur et à mesure que vous apprenez, vous pourrez discriminer de plus en plus, et si le résultat est correct, vous pourrez porter un jugement proche de 0, et si le résultat est incorrect, vous pourrez porter un jugement proche de 1.
Ceci est le résultat de l'utilisation de sigmoïde pour la fonction d'activation de sortie. sigmoïde a pour effet de normaliser la valeur dans la plage de 0 à 1, ce qui indique le succès ou l'échec de la reconnaissance sous forme de probabilité.
Suite à la validation, le taux de reconnaissance des numéros manuscrits était de 84,7%. Si vous pouvez obtenir un tel résultat avec l'algorithme primitif ci-dessus, vous pouvez dire que vous avez réussi à reconnaître les nombres manuscrits pour le moment.
On m'a fait remarquer que la signification du résultat de l'exécution est difficile à lire, je vais donc ajouter une explication.
Commençons par affiner la gamme des résultats d'exécution.
La figure ci-dessus est un graphique du taux d'erreur jusqu'à l'essai 29970 ... 30000. Vous pouvez voir la périodicité de ce graphique. La périodicité pour chaque type de nombre (0 ... 9), comme une erreur faible lorsque le chiffre des unités est 0 ou 1 et une erreur élevée lorsque le chiffre des unités est 9
Cette vibration est due à l'algorithme d'apprentissage. Dans l'algorithme utilisé cette fois, Shioume, comme l'apprentissage de 1 après l'apprentissage de 0, est amené à apprendre à chaque fois les types de nombres suivants. Par conséquent, le taux d'erreur fluctue considérablement en fonction du nombre d'essais. Il n'y a pas de lien direct avec des essais consécutifs, mais avec des essais basés sur 10. Vous apprenez la reconnaissance de 0 en essayant 0 → 10 → 20 → 30 et la reconnaissance de 1 en essayant 1 → 11 → 21.
Le taux de reconnaissance moyen diffère en fonction de chaque nombre. À un moment donné, un modèle peut bien reconnaître 0 et 9 non. C'est pourquoi les perceptions varient et semblent vibrer.
Et à mesure que l'apprentissage progresse, le modèle apprend ce qu'on appelle une «valeur idéale». Le taux d'erreur augmentera également. En effet, lorsque la valeur idéale est solidifiée, le degré de déviation de la valeur d'entrée devient plus clair qu'à l'état neutre. Regardons un exemple de la valeur idéale et du degré de déviation.
La figure ci-dessus montre le résultat de la saisie d'une partie de l'ensemble de validation 0 et son taux d'erreur. Le taux d'erreur est la dernière partie du délimiteur de soulignement dans le nom de fichier, avant l'extension. Le numéro d'index de l'image est avant le taux d'erreur. Dans cette image, la 93ème image d'entrée montre le taux d'erreur le plus élevé (0,4708). Le modèle a appris qu'il était difficile de reconnaître que c'était 0 quand j'ai vu cette forme terne. De plus, dans l'image ci-dessus, le n ° 98 a le taux d'erreur le plus bas, de sorte qu'il est également appris que 0 incliné vers la droite est le plus proche de la forme idéale de 0.
Cette fois, j'ai montré une implémentation simple d'un réseau neuronal. Cependant, avec l'algorithme actuel, il y a encore des mécontentements en termes de nombre de formations et d'erreurs. La prochaine fois, je résoudrai ce mécontentement avec plusieurs approches.
Recommended Posts