Utilisez Chainer pour apprendre les idées de base de l'apprentissage profond.
chainer.Variable
Dans Chainer, les variables sont décrites comme une classe appelée Variable.
import numpy as np
from chainer import Variable
x1 = Variable(np.array([0.12]).astype(np.float32))
x2 = Variable(np.array([0.34]).astype(np.float32))
x3 = Variable(np.array([0.56]).astype(np.float32))
Effectuer un "calcul à terme" par le calcul suivant. En deep learning, ces coefficients (0,5, 0,3, 0,2, etc. ci-dessous) sont appelés "gradients", et le but du calcul est de trouver la valeur optimale du gradient.
z = 0.5 * x1 + 0.3 * x2 + 0.2 * x3
Le résultat de l'opération est également un objet de la classe Variable.
z
variable([0.274])
Vous pouvez utiliser l'attribut .data pour référencer l'objet numpy.ndarray qui est le contenu des données.
z.data
array([0.274], dtype=float32)
Effectuez le "calcul inversé" comme suit. Le but du calcul inverse est de "rétropropropager" l'erreur dans le résultat du calcul avant et d'affiner le "coefficient" mentionné ci-dessus.
z.backward()
Le calcul inversé donne la "valeur différentielle" nécessaire lors du réglage fin des coefficients de chaque variable.
x1.grad, x2.grad, x3.grad
(array([0.5], dtype=float32),
array([0.3], dtype=float32),
array([0.2], dtype=float32))
Jusqu'à présent, les variables étaient unidimensionnelles, mais vous pouvez également utiliser des tableaux multidimensionnels comme indiqué ci-dessous.
x1 = Variable(np.array([0.12, 0.21]).astype(np.float32))
x2 = Variable(np.array([0.34, 0.43]).astype(np.float32))
x3 = Variable(np.array([0.56, 0.65]).astype(np.float32))
z = 0.5 * x1 + 0.3 * x2 + 0.2 * x3
z
variable([0.274, 0.364])
Si la variable est multidimensionnelle, vous devez connaître à l'avance la dimension de la pente de la fonction avant de faire le "calcul inverse".
z.grad = np.ones(2, dtype=np.float32)
z.backward()
x1.grad, x2.grad, x3.grad
(array([0.5, 0.5], dtype=float32),
array([0.3, 0.3], dtype=float32),
array([0.2, 0.2], dtype=float32))
chainer.links.Linear
Chainer fournit une fonction de transformation linéaire comme chainer.links.Linear utilisé lors du passage de données d'une couche à l'autre dans un réseau neuronal (NN) qui effectue un apprentissage en profondeur. Transformation linéaire
Il est exprimé comme. Avant d'utiliser chainer.links.Linear, exprimons une transformation linéaire avec numpy.
import numpy as np
W = np.array([[ 5, 1, -2 ],
[ 3, -5, -1 ]], dtype=np.float32)
b = np.array([2, -3], dtype=np.float32)
S'il n'y a qu'une seule donnée d'entrée (une seule donnée composée de trois variables), elle peut être calculée comme suit.
x = np.array([0, 1, 2])
y = x.dot(W.T) + b
y
array([ -1., -10.])
S'il y a 5 données d'entrée (5 données composées de 3 variables), elles peuvent être calculées comme suit. De cette façon, la force du calcul matriciel est qu'il peut être calculé en parallèle même s'il y a une grande quantité de données.
x = np.array(range(15)).astype(np.float32).reshape(5, 3)
x
array([[ 0., 1., 2.],
[ 3., 4., 5.],
[ 6., 7., 8.],
[ 9., 10., 11.],
[12., 13., 14.]], dtype=float32)
y = x.dot(W.T) + b
y
array([[ -1., -10.],
[ 11., -19.],
[ 23., -28.],
[ 35., -37.],
[ 47., -46.]], dtype=float32)
Un calcul similaire peut être réalisé avec chainer.links.Linear.
import chainer.links as L
h = L.Linear(3,2) #Fonction d'action linéaire y qui entre un vecteur tridimensionnel et produit un vecteur bidimensionnel= Wx + b
h.W.data #L'aléatoire est entré par défaut
array([[ 0.5469049 , -0.35929427, -0.9921321 ],
[ 1.4973897 , 0.620568 , 0.78245926]], dtype=float32)
h.b.data #Contient 0 vecteur par défaut
array([0., 0.], dtype=float32)
x = Variable(np.array(range(15)).astype(np.float32).reshape(5, 3))
x.data # Variable.data est un objet tableau de Numpy
array([[ 0., 1., 2.],
[ 3., 4., 5.],
[ 6., 7., 8.],
[ 9., 10., 11.],
[12., 13., 14.]], dtype=float32)
y = h(x)
y.data
array([[ -2.3435585, 2.1854866],
[ -4.757123 , 10.886737 ],
[ -7.170687 , 19.587988 ],
[ -9.584251 , 28.289238 ],
[-11.997816 , 36.990486 ]], dtype=float32)
x.data.dot(h.W.data.T) + h.b.data #vérification des comptes
array([[ -2.3435585, 2.1854866],
[ -4.757123 , 10.886737 ],
[ -7.170687 , 19.587988 ],
[ -9.584251 , 28.289238 ],
[-11.997816 , 36.990486 ]], dtype=float32)
chainer.functions
Chainer fournit diverses fonctions dans chainer.functions qui prennent des objets de la classe Variable comme arguments. Un exemple typique est l'erreur quadratique moyenne chainer.functions.mean_squared_error.
import chainer.functions as F
y_pred = Variable(np.array([0.1, 0.2, 0.3]).astype(np.float32))
y_real = Variable(np.array([0.2, 0.1, 0.3]).astype(np.float32))
loss = F.mean_squared_error(y_pred, y_real)
loss
variable(0.00666667)
Maintenant, comme pratique pour Chainer, faisons une régression multiple linéaire. En tant que données à traiter, les données Iris, souvent utilisées dans le domaine de l'apprentissage automatique, sont traitées.
import numpy as np
from sklearn import datasets
iris = datasets.load_iris() #Lecture des données d'iris
data = iris.data.astype(np.float32)
X = data[:, :3] #Les trois premières données de mesure de l'iris sont utilisées comme variables explicatives.
Y = data[:, 3].reshape(len(data), 1) #Soit la dernière variable objective.
#Soit les données impaires les données de l'enseignant et les données paires les données de test.
index = np.arange(Y.size)
X_train = X[index[index % 2 != 0], :] #Variable explicative (données enseignants)
X_test = X[index[index % 2 == 0], :] #Variable explicative (données de test)
Y_train = Y[index[index % 2 != 0], :] #Variable objective (données enseignants)
Y_test = Y[index[index % 2 == 0], :] #Variable objective (données de test)
chainer.Sequential
Dans chainer.Sequential, définissez la structure du réseau neuronal.
import chainer.links as L
from chainer import Sequential
n_input = 3 #Les données d'entrée sont de 3 variables
n_output = 1 #Les données de sortie sont une variable
mlr = Sequential( #Définir un réseau de neurones
L.Linear(n_input, n_output) #Réseau neuronal constitué d'une seule couche
)
Lorsqu'il est défini pour la première fois, il contient un nombre aléatoire sous forme de coefficient (gradient).
mlr[0].W.data, mlr[0].b.data #Vous pouvez vous référer au coefficient de cette manière
(array([[ 0.8395325 , 0.26789278, -0.4547218 ]], dtype=float32),
array([0.], dtype=float32))
Vous pouvez effectuer un «calcul à terme» comme suit. Cependant, comme le coefficient reste une valeur initiale aléatoire, la valeur prédite obtenue est également erratique.
Y_pred = mlr(X_test) #Calcul à terme
Y_pred
variable([[4.5826297],
[4.211921 ],
[4.525466 ],
[4.136074 ],
[3.8342214],
[4.842596 ],
[4.196824 ],
[5.3951936],
[4.9871187],
[5.0303006],
[4.6712837],
[4.3715415],
[4.07662 ],
[4.380943 ],
[4.6397934],
[4.132669 ],
[4.7818465],
[4.2620945],
[4.9639153],
[3.9064832],
[4.544149 ],
[3.9600616],
[4.435637 ],
[4.5720534],
[4.758643 ],
[4.596792 ],
[4.395105 ],
[4.11534 ],
[4.0359087],
[4.226083 ],
[3.1419218],
[3.807672 ],
[3.841272 ],
[3.458812 ],
[3.7482173],
[3.6278338],
[3.73065 ],
[4.1945934],
[4.276256 ],
[3.7678359],
[3.5324283],
[3.8191838],
[3.2909057],
[4.318143 ],
[3.6407008],
[3.313174 ],
[3.7469225],
[3.5148606],
[3.6523929],
[3.5871825],
[3.44477 ],
[4.0815 ],
[3.623253 ],
[2.7371933],
[3.657213 ],
[3.995137 ],
[4.01153 ],
[3.300307 ],
[3.7596698],
[4.02334 ],
[4.058117 ],
[4.1678634],
[3.9169993],
[3.7725363],
[3.5766659],
[4.188837 ],
[3.5766659],
[3.2712274],
[3.653448 ],
[3.6582088],
[3.908893 ],
[3.2735178],
[3.9169993],
[3.6851778],
[3.660439 ]])
chainer.optimizers
chainer.optimizers propose une variété de techniques d'optimisation. L'un d'eux est la descente de gradient stochastique (SGD).
from chainer import optimizers
optimizer = optimizers.SGD(lr=0.01) #Sélectionnez SGD comme méthode d'optimisation
optimizer.setup(mlr) #Configurer le réseau défini
<chainer.optimizers.sgd.SGD at 0x7f2e090bb7f0>
Comparez la valeur prédite Y_pred obtenue précédemment avec la valeur réelle observée Y_train pour obtenir son erreur de racine carrée moyenne MSE. Il existe plusieurs autres choix pour définir l'erreur. Dans l'apprentissage en profondeur, ces erreurs sont appelées «perte» et la fonction de recherche de perte est appelée «fonction de perte». L'apprentissage en profondeur vise à minimiser cette perte.
import chainer.functions as F
loss = F.mean_squared_error(Y_pred, Y_train)
loss
variable(9.235707)
Faites le calcul inverse et mettez à jour le dégradé pour réduire l'erreur comme suit:
mlr.cleargrads() #Initialisation du gradient
loss.backward() #Calcul inversé
optimizer.update() #Mise à jour du dégradé
Voyons que la valeur de la pente a changé.
mlr[0].W.data, mlr[0].b.data
(array([[ 0.51864076, 0.08801924, -0.63399327]], dtype=float32),
array([-0.05653327], dtype=float32))
Répétez le calcul ci-dessus jusqu'à ce que la perte converge.
%time
for i in range(50):
Y_pred = mlr(X_test) #Calcul à terme
loss = F.mean_squared_error(Y_pred, Y_train) #Calcul d'erreur
mlr.cleargrads() #Initialisation du gradient
loss.backward() #Calcul inversé
optimizer.update() #Mise à jour du dégradé
CPU times: user 3 µs, sys: 1 µs, total: 4 µs
Wall time: 8.11 µs
Assurez-vous que la perte est réduite.
loss
variable(0.15386367)
Le flux ci-dessus peut être résumé comme suit.
%time
import numpy as np
import chainer.links as L
import chainer.functions as F
from chainer import Sequential
from chainer import optimizers
from sklearn import datasets
iris = datasets.load_iris()
data = iris.data.astype(np.float32)
X = data[:, :3]
Y = data[:, 3].reshape(len(data), 1)
index = np.arange(Y.size)
X_train = X[index[index % 2 != 0], :]
X_test = X[index[index % 2 == 0], :]
Y_train = Y[index[index % 2 != 0], :]
Y_test = Y[index[index % 2 == 0], :]
n_input = 3
n_output = 1
mlr = Sequential(
L.Linear(n_input, n_output)
)
optimizer = optimizers.SGD(lr=0.01)
optimizer.setup(mlr)
loss_history = []
for i in range(100):
Y_pred = mlr(X_train)
loss = F.mean_squared_error(Y_pred, Y_train)
loss_history.append(np.mean(loss.data))
mlr.cleargrads()
loss.backward()
optimizer.update()
CPU times: user 2 µs, sys: 1e+03 ns, total: 3 µs
Wall time: 4.77 µs
loss
variable(0.05272739)
mlr[0].W.data, mlr[0].b.data
(array([[ 0.11841334, -0.2642416 , 0.324636 ]], dtype=float32),
array([0.08475045], dtype=float32))
J'ai enregistré la valeur de la perte pour chaque calcul itératif, je vais donc l'illustrer et voir si la perte a convergé.
%matplotlib inline
import matplotlib.pyplot as plt
plt.plot(loss_history)
[<matplotlib.lines.Line2D at 0x7f2e08bfcbe0>]
Il semble qu'il a convergé. Regardons maintenant le graphique y-y comparant les valeurs prédites et mesurées. Plus elle est proche de la diagonale, meilleure est la prédiction.
%matplotlib inline
import matplotlib.pyplot as plt
plt.figure(figsize=(6,6))
plt.scatter(Y_train.flatten(), mlr(X_train).data.flatten(), alpha=0.5, label='train')
plt.plot([min(Y), max(Y)], [min(Y), max(Y)])
plt.grid()
plt.legend()
plt.xlabel('Observed')
plt.ylabel('Predicted')
plt.show()
Ensuite, effectuons une régression logistique, qui est une méthode de retour à la fonction sigmoïde (fonction logistique) et qui est également utilisée comme méthode de classification.
Cette fois, utilisons les quatre données de mesure d'Ayame comme variable explicative et les variétés d'Ayame (3 types) comme variable objective.
import numpy as np
from sklearn import datasets
iris = datasets.load_iris() #Lecture des données d'iris
X = iris.data.astype(np.float32) #4 variables comme variables explicatives
Y = iris.target #Variétés d'Ayame (3 types) comme variables objectives
#Une variété d'iris-Convertir en vecteur chaud.
Y_ohv = np.zeros(3 * Y.size).reshape(Y.size, 3).astype(np.float32)
for i in range(Y.size):
Y_ohv[i, Y[i]] = 1.0 # one-hot vector
#Soit les données impaires les données de l'enseignant et les données paires les données de test.
index = np.arange(Y.size)
X_train = X[index[index % 2 != 0], :] #Variable explicative (données enseignants)
X_test = X[index[index % 2 == 0], :] #Variable explicative (données de test)
Y_train = Y_ohv[index[index % 2 != 0], :] #Objectif, variable 1-vecteur chaud (données de l'enseignant)
Y_test = Y_ohv[index[index % 2 == 0], :] #Objectif, variable 1-vecteur chaud (données de test)
Y_ans_train = Y[index[index % 2 != 0]] #Variable objective (données enseignants)
Y_ans_test = Y[index[index % 2 == 0]] #Variable objective (données de test)
from chainer import Sequential
import chainer.links as L
import chainer.functions as F
n_input = 4 #L'entrée est de 4 variables
n_output = 3 #La sortie est 3 variables
lr = Sequential(
L.Linear(n_input, n_output), #Transformation linéaire
F.sigmoid, #Fonction Sigmaid
F.softmax #Fonction Softmax qui se convertit en un nombre réel positif dont la somme est 1.
)
from chainer import optimizers
optimizer = optimizers.SGD(lr=0.01)
optimizer.setup(lr)
<chainer.optimizers.sgd.SGD at 0x7f2e0878b7b8>
Y_pred = lr(X_train)
loss = F.mean_squared_error(Y_pred, Y_train)
loss
variable(0.21429048)
lr.cleargrads()
loss.backward()
optimizer.update()
Y_pred = lr(X_train)
loss = F.mean_squared_error(Y_pred, Y_train)
loss
variable(0.21422786)
%time
for i in range(50):
Y_pred = lr(X_train)
loss = F.mean_squared_error(Y_pred, Y_train)
lr.cleargrads()
loss.backward()
optimizer.update()
CPU times: user 7 µs, sys: 1 µs, total: 8 µs
Wall time: 28.1 µs
loss
variable(0.21126282)
Le flux ci-dessus peut être résumé comme suit.
%time
import numpy as np
import chainer.links as L
import chainer.functions as F
from chainer import Sequential
from chainer import optimizers
from sklearn import datasets
iris = datasets.load_iris()
X = iris.data.astype(np.float32)
Y = iris.target
Y_ohv = np.zeros(3 * Y.size).reshape(Y.size, 3).astype(np.float32)
for i in range(Y.size):
Y_ohv[i, Y[i]] = 1.0 # one-hot vector
index = np.arange(Y.size)
X_train = X[index[index % 2 != 0], :]
X_test = X[index[index % 2 == 0], :]
Y_train = Y_ohv[index[index % 2 != 0], :]
Y_test = Y_ohv[index[index % 2 == 0], :]
Y_ans_train = Y[index[index % 2 != 0]]
Y_ans_test = Y[index[index % 2 == 0]]
n_input = 4
n_output = 3
lr = Sequential(
L.Linear(n_input, n_output),
F.sigmoid,
F.softmax
)
optimizer = optimizers.SGD(lr=0.01)
optimizer.setup(lr)
loss_history = []
for i in range(100000):
Y_pred = lr(X_train)
loss = F.mean_squared_error(Y_pred, Y_train)
loss_history.append(np.mean(loss.data))
lr.cleargrads()
loss.backward()
optimizer.update()
CPU times: user 2 µs, sys: 0 ns, total: 2 µs
Wall time: 5.01 µs
loss
variable(0.14579579)
J'ai enregistré la valeur de la perte pour chaque calcul itératif, je vais donc l'illustrer et voir si la perte a convergé.
%matplotlib inline
import matplotlib.pyplot as plt
plt.plot(loss_history)
[<matplotlib.lines.Line2D at 0x7f2e06445080>]
lr[0].W.data, lr[0].b.data
(array([[ 0.7060194 , 1.5789627 , -2.7305322 , -1.5006719 ],
[-0.6907905 , -0.43505952, -0.78199637, -0.06515903],
[-1.7571408 , -2.1365883 , 2.8683107 , 2.772224 ]],
dtype=float32),
array([ 0.2556363 , -0.15823539, -0.9368208 ], dtype=float32))
Puisque la dernière couche est une fonction softmax qui convertit la somme en un nombre réel positif, la sortie peut être considérée comme "la probabilité qu'elle puisse être considérée comme de ce type". Trouvons le taux de réponse correct lorsque la variété avec la probabilité maximale est la «variété prédite».
Y_pred = lr(X_train)
nrow, ncol = Y_pred.data.shape
count = 0
for i in range(nrow):
cls = np.argmax(Y_pred.data[i, :])
if cls == Y_ans_train[i]:
count += 1
print(count, " / ", nrow, " = ", count / nrow)
50 / 75 = 0.6666666666666666
Jusqu'à présent, j'ai créé des modèles de régression multiple linéaire et de régression logistique à l'aide de Chainer. De la même manière, si vous épaississez la couche, cela devient un «apprentissage profond». Le modèle le plus simple d'apprentissage en profondeur est le perceptron multicouche.
%time
import numpy as np
from chainer import Sequential
from chainer import optimizers
import chainer.links as L
import chainer.functions as F
from sklearn import datasets
iris = datasets.load_iris()
X = iris.data.astype(np.float32)
Y = iris.target
Y_ohv = np.zeros(3 * Y.size).reshape(Y.size, 3).astype(np.float32)
for i in range(Y.size):
Y_ohv[i, Y[i]] = 1.0 # one-hot vector
index = np.arange(Y.size)
X_train = X[index[index % 2 != 0], :]
X_test = X[index[index % 2 == 0], :]
Y_train = Y_ohv[index[index % 2 != 0], :]
Y_test = Y_ohv[index[index % 2 == 0], :]
Y_ans_train = Y[index[index % 2 != 0]]
Y_ans_test = Y[index[index % 2 == 0]]
n_input = 4
n_hidden = 6
n_output = 3
mlp = Sequential(
L.Linear(n_input, n_hidden),
F.sigmoid,
L.Linear(n_hidden, n_output),
F.softmax
)
optimizer = optimizers.SGD(lr=0.01)
optimizer.setup(mlp)
loss_history = []
for i in range(100000):
Y_pred = mlp(X_train)
loss = F.mean_squared_error(Y_pred, Y_train)
loss_history.append(np.mean(loss.data))
mlp.cleargrads()
loss.backward()
optimizer.update()
CPU times: user 3 µs, sys: 0 ns, total: 3 µs
Wall time: 5.48 µs
loss
variable(0.01375966)
%matplotlib inline
import matplotlib.pyplot as plt
plt.plot(loss_history)
[<matplotlib.lines.Line2D at 0x7f2e08746fd0>]
Y_pred = mlp(X_train)
nrow, ncol = Y_pred.data.shape
count = 0
for i in range(nrow):
cls = np.argmax(Y_pred.data[i, :])
if cls == Y_ans_train[i]:
count += 1
print(count, " / ", nrow, " = ", count / nrow)
74 / 75 = 0.9866666666666667
import numpy as np
from sklearn import datasets
iris = datasets.load_iris()
data = iris.data.astype(np.float32)
X = data[:, :3]
Y = data[:, 3].reshape(len(data), 1)
index = np.arange(Y.size)
X_train = X[index[index % 2 != 0], :]
X_test = X[index[index % 2 == 0], :]
Y_train = Y[index[index % 2 != 0], :]
Y_test = Y[index[index % 2 == 0], :]
%time
import numpy as np
from chainer import Sequential
from chainer import optimizers
import chainer.links as L
import chainer.functions as F
n_input = 3
n_hidden = 6
n_output = 1
mlpr = Sequential(
L.Linear(n_input, n_hidden),
F.sigmoid,
L.Linear(n_hidden, n_output)
)
optimizer = optimizers.SGD(lr=0.01)
optimizer.setup(mlpr)
loss_history = []
for i in range(10000):
Y_pred = mlpr(X_train)
loss = F.mean_squared_error(Y_pred, Y_train)
loss_history.append(np.mean(loss.data))
mlpr.cleargrads()
loss.backward()
optimizer.update()
CPU times: user 4 µs, sys: 0 ns, total: 4 µs
Wall time: 8.82 µs
loss
variable(0.04921096)
%matplotlib inline
import matplotlib.pyplot as plt
plt.plot(loss_history)
[<matplotlib.lines.Line2D at 0x7f2e064200f0>]
%matplotlib inline
import matplotlib.pyplot as plt
plt.figure(figsize=(6,6))
plt.scatter(Y_train.flatten(), mlpr(X_train).data.flatten(), alpha=0.5, label='train')
plt.plot([min(Y), max(Y)], [min(Y), max(Y)])
plt.grid()
plt.legend()
plt.xlabel('Observed')
plt.ylabel('Predicted')
plt.show()
Un auto-encodeur est un réseau neuronal qui revient à lui-même. Le convertisseur de couche d'entrée vers couche intermédiaire est appelé le codeur codeur, et le convertisseur de couche intermédiaire vers couche de sortie est appelé décodeur décodeur. La "réduction de dimension" (réduction de dimension) peut être effectuée en réduisant le nombre de neurones dans la couche intermédiaire à moins que les données d'entrée.
import numpy as np
from sklearn import datasets
iris = datasets.load_iris()
X = iris.data.astype(np.float32)
%time
import numpy as np
from chainer import Sequential
from chainer import optimizers
import chainer.links as L
import chainer.functions as F
n_input = 4
n_hidden = 2
n_output = 4
ae = Sequential(
L.Linear(n_input, n_hidden),
F.sigmoid,
L.Linear(n_hidden, n_output),
)
optimizer = optimizers.SGD(lr=0.01)
optimizer.setup(ae)
loss_history = []
for i in range(10000):
X_pred = ae(X)
loss = F.mean_squared_error(X_pred, X)
loss_history.append(np.mean(loss.data))
ae.cleargrads()
loss.backward()
optimizer.update()
CPU times: user 5 µs, sys: 0 ns, total: 5 µs
Wall time: 9.54 µs
loss
variable(0.09372737)
%matplotlib inline
import matplotlib.pyplot as plt
plt.plot(loss_history)
[<matplotlib.lines.Line2D at 0x7f2e06699a58>]
latent = F.sigmoid(ae[0](X))
%matplotlib inline
import matplotlib.pyplot as plt
plt.scatter(latent.data[0:50, 0], latent.data[0:50, 1], alpha=0.5)
plt.scatter(latent.data[50:100, 0], latent.data[50:100, 1], alpha=0.5)
plt.scatter(latent.data[100:150, 0], latent.data[100:150, 1], alpha=0.5)
plt.grid()
Recommended Posts