Pour le texte de la question, certains candidats pour le texte de la réponse sont donnés C'est un système qui sélectionne automatiquement la bonne réponse parmi elles.
L'ensemble de données utilisé est
Réponse aux questions du manuel d'Allen AI.
J'ai préparé train.json et val.json sous "./nlp_data/".
Utilisez train.json comme données d'entraînement et val.json comme données d'évaluation.
Or, en général, la tâche de traitement du langage naturel nécessite un prétraitement des données.
Utilisez la ségrégation comme pré-processus.
La séparation est la division d'une phrase en mots.
Dans le cas de l'anglais, il est nécessaire d'écrire séparément, de normaliser les caractères et les mots d'identification.
Et lorsque vous utilisez l'apprentissage profond dans le traitement du langage naturel, toutes les longueurs de phrase de l'entrée doivent être identiques.
La raison est que sinon, les opérations matricielles ne peuvent pas être effectuées.
L'unification de la longueur de cette phrase d'entrée est appelée Padding.
Les phrases courtes doivent être ajoutées avec 0 et les phrases trop longues doivent être supprimées.
En ce qui concerne la normalisation anglaise, cette fois, nous ne traiterons que du processus le plus basique d'unification en majuscules ou minuscules.
Lorsque la phrase anglaise est donnée sous forme de chaîne de caractères
s = "I am Darwin."
s = s.lower()
print(s)
# => "i am darwin."
Vient ensuite la division. Un des outils utilisés pour la division anglaise
Il y a quelque chose qui s'appelle nltk.
Dans nltk, vous pouvez utiliser des mots-clés, des racines, etc. en plus de l'écriture de division. Cette fois, par souci de simplicité, je n'utiliserai que la division.
from nltk.tokenize import word_tokenize
t = "he isn't darwin."
t = word_tokenize(t)
print(t)
# => ['he', 'is', "n't", 'darwin', '.']
De cette façon, n'est pas peut être divisé en est et n't, et le point peut également être séparé en un mot.
Cliquez ici pour des exemples d'utilisation
import json
from nltk.tokenize import word_tokenize
import nltk
nltk.download('punkt')
with open("./nlp_data/train.json") as f:
train = json.load(f)
#train est une liste et chaque élément stocke les questions, les candidats de réponse et les réponses sous forme de données de type dictionnaire.
# train[0] = {'answerChoices': {'a': 'solid Earth.',
# 'b': 'Earths oceans.',
# 'c': 'Earths atmosphere.',
# 'd': 'all of the above'},
# 'correctAnswer': 'd',
# 'question': 'Earth science is the study of'}
target = train[0]["question"]
#Unifié en minuscules
target = target.lower()
#Partage
target = word_tokenize(target)
print(target)
Parce que le mot lui-même ne peut pas être donné au réseau neuronal comme entrée Doit être converti en identifiant.
Qu'est-ce qu'un identifiant ici?
Correspond à une ligne dans la matrice d'intégration.
De plus, si vous attribuez un identifiant à tous les mots qui apparaissent dans les données Dans de nombreux cas, le nombre total de vocabulaire devient énorme.
Par conséquent, ne donnez un identifiant qu'aux mots dont la fréquence est supérieure à un certain niveau. Convertit les données en une colonne d'ID.
Aussi, type de dictionnaire.get(['key'])Correspond à Key par
Vous pouvez obtenir la valeur de Value.
dict_ = {'key1': 'earth','key2': 'science', 'key3':'is','key4': 'the', 'key5':'study', 'key6':'of'}
print(dict_['key1'])
print(dict_.get('key1'))
Cliquez ici pour des exemples d'utilisation
import json
from nltk.tokenize import word_tokenize
import nltk
nltk.download('punkt')
with open("./nlp_data/train.json", "r") as f:
train = json.load(f)
def preprocess(s):
s = s.lower()
s = word_tokenize(s)
return s
sentences = []
for t in train:
q = t['question']
q = preprocess(q)
sentences.append(q)
for i, a in t['answerChoices'].items():
a = preprocess(a)
sentences.append(a)
vocab = {}
for s in sentences:
for w in s:
# vocab.get()Calculez la fréquence de chaque mot avec
vocab[w] = vocab.get(w, 0) + 1
word2id = {}
word2id['<unk>'] = 0
for w, v in vocab.items():
if not w in word2id and v >= 2:
# len()Donnez au mot un identifiant avec
word2id[w] = len(word2id)
target = preprocess(train[0]["question"])
target = [word2id.get(w, 0) for w in target]
print(target)
Padding
Lors de l'exécution d'un apprentissage en profondeur, il n'est pas possible d'effectuer des opérations matricielles comme c'est le cas pour des données de différentes longueurs telles que des phrases.
Ajoutez de force 0 pour l'identifiant factice à la fin ou supprimez autant de mots que nécessaire à la fin de la phrase
Vous devez compléter (et tronquer) les données d'entrée.
keras a une fonction pratique pour cela, je vais donc l'utiliser cette fois.
import numpy as np
from keras.preprocessing.sequence import pad_sequences
s = [[1,2], [3,4,5], [6,7,8], [9,10,11,12,13,14]]
s = pad_sequences(s, maxlen=5, dtype=np.int32, padding='post', truncating='post', value=0)
print(s)
# => array([[ 1, 2, 0, 0, 0],
# [ 3, 4, 5, 0, 0],
# [ 6, 7, 8, 0, 0],
# [ 9, 10, 11, 12, 13]], dtype=int32)
Après le remplissage et la troncature de cette manière, il revient sous la forme d'un tableau numpy.
L'explication de l'argument est la suivante.
maxlen:Unifier la longueur
dtype:Type de données
padding: 'pre'Ou'post'を指定し、前と後ろのどちらにpaddingするOuを決める
truncating: 'pre'Ou'post'を指定し、前と後ろのどちらをtruncatingするOu決める
value:Valeur utilisée lors du remplissage
Cliquez ici pour des exemples d'utilisation
import numpy as np
from keras.preprocessing.sequence import pad_sequences
#Utilisez ceci pour l'argument.
maxlen = 10
dtype = np.int32
padding = 'post'
truncating = 'post'
value = 0
#Les données
s = [[1,2,3,4,5,6], [7,8,9,10,11,12,13,14,15,16,17,18], [19,20,21,22,23]]
# padding,Veuillez tronquer.
s = pad_sequences(s,maxlen=10,dtype=np.int32,padding=padding,truncating=truncating,value=value)
print(s)
Attention-based QA-LSTM
Désormais, nous allons enfin implémenter le système de sélection des phrases de réponse.
Pour le modèle d'apprentissage
Attention-based QA-Nous utiliserons une version améliorée de LSTM qui est facile à comprendre.
La vue d'ensemble du modèle est un diagramme.
① Tout d'abord, saisissez la question et la réponse séparément dans BiLSTM.
② Suivant Attention de la question à la réponse Vous pouvez obtenir des informations de réponse en tenant compte de la question.
(3) Après cela, le vecteur d'état caché à chaque instant de Question est moyenné (regroupement moyen) pour obtenir le vecteur q.
④ D'autre part, après avoir appliqué Attention de la question, prenez la moyenne des vecteurs d'état cachés à chaque fois de réponse. Obtenez le vecteur a.
⑤ Enfin, ces deux vecteurs
comme
Combinez les vecteurs dans l'équation ci-dessus La sortie se compose de deux unités via un réseau neuronal à propagation directe et la fonction Softmax.
Cette méthode d'adhésion est basée sur la célèbre méthode appelée InferSent annoncée par la recherche Facebook.
La couche de sortie de ce modèle a deux unités Nous apprendrons à prédire [1,0] pour les phrases à réponse correcte et [0,1] pour les phrases à réponse incorrecte.
Bidirectional LSTM(BiLSTM)Quel est
Lors de la reconnaissance d'une expression unique, vous pouvez capturer des informations contextuelles dans les directions gauche et droite en lisant par l'arrière.
Cliquez ici pour des exemples d'utilisation
from keras.layers import Input, Dense, Dropout
from keras.layers.embeddings import Embedding
from keras.layers.recurrent import LSTM
from keras.layers.wrappers import Bidirectional
from keras.models import Model
vocab_size = 1000 #Nombre de vocabulaire à gérer
embedding_dim = 100 #Dimensions du vecteur Word
seq_length1 = 20 #Longueur de la question
seq_length2 = 10 #Longueur de la réponse
lstm_units = 200 #Nombre de dimensions du vecteur d'état caché de LSTM
embedding = Embedding(input_dim=vocab_size, output_dim=embedding_dim)
input1 = Input(shape=(seq_length1,))
embed1 = embedding(input1)
bilstm1 = Bidirectional(LSTM(lstm_units, return_sequences=True), merge_mode='concat')(embed1)
h1 = Dropout(0.2)(bilstm1)
model1 = Model(inputs=input1, outputs=h1)
input2 = Input(shape=(seq_length2,))
embed2 = embedding(input2)
bilstm2 = Bidirectional(LSTM(lstm_units, return_sequences=True), merge_mode='concat')(embed2)
h2 = Dropout(0.2)(bilstm2)
model2 = Model(inputs=input2, outputs=h2)
model1.summary()
model2.summary()
Passons en revue le contenu de la figure ci-dessous.
Notez que c'est une attention de question à réponse.
Voici un exemple d'utilisation, qui est ajouté à la section précédente.
from keras.layers import Input, Dense, Dropout
from keras.layers.embeddings import Embedding
from keras.layers.recurrent import LSTM
from keras.layers.wrappers import Bidirectional
from keras.layers.merge import dot, concatenate
from keras.layers.core import Activation
from keras.models import Model
batch_size = 32 #Taille du lot
vocab_size = 1000 #Nombre de vocabulaire à gérer
embedding_dim = 100 #Dimensions du vecteur Word
seq_length1 = 20 #Longueur de la question
seq_length2 = 10 #Longueur de la réponse
lstm_units = 200 #Nombre de dimensions du vecteur d'état caché de LSTM
hidden_dim = 200 #Nombre de dimensions du vecteur de sortie final
embedding = Embedding(input_dim=vocab_size, output_dim=embedding_dim)
input1 = Input(shape=(seq_length1,))
embed1 = embedding(input1)
bilstm1 = Bidirectional(LSTM(lstm_units, return_sequences=True), merge_mode='concat')(embed1)
h1 = Dropout(0.2)(bilstm1)
input2 = Input(shape=(seq_length2,))
embed2 = embedding(input2)
bilstm2 = Bidirectional(LSTM(lstm_units, return_sequences=True), merge_mode='concat')(embed2)
h2 = Dropout(0.2)(bilstm2)
#Calculez le produit pour chaque élément
product = dot([h2, h1], axes=2) #Taille:[Taille du lot, longueur de la réponse, longueur de la question]
a = Activation('softmax')(product)
c = dot([a, h1], axes=[2, 1])
c_h2 = concatenate([c, h2], axis=2)
h = Dense(hidden_dim, activation='tanh')(c_h2)
model = Model(inputs=[input1, input2], outputs=h)
model.summary()
Implémenter de la mise en commun moyenne à la couche de sortie
Notez que nous utilisons enfin la fonction softmax.
pour une mise en commun moyenne
from keras.layers.pooling import AveragePooling1D
y = AveragePooling1D(pool_size=2, strides=1)(x)
La taille de x est [batch_size, steps, features]
La taille de y est [batch_size, downsampled_steps, features].
Cliquez ici pour des exemples d'utilisation
from keras.layers import Input, Dense, Dropout, Lambda, Reshape
from keras.layers.embeddings import Embedding
from keras.layers.recurrent import LSTM
from keras.layers.wrappers import Bidirectional
from keras.layers.merge import dot, concatenate, subtract, multiply
from keras.layers.core import Activation
from keras.layers.pooling import AveragePooling1D
from keras import backend as K
from keras.models import Model
batch_size = 32 #Taille du lot
vocab_size = 1000 #Nombre de vocabulaire à gérer
embedding_dim = 100 #Dimensions du vecteur Word
seq_length1 = 20 #Longueur de la question
seq_length2 = 10 #Longueur de la réponse
lstm_units = 200 #Nombre de dimensions du vecteur d'état caché de LSTM
hidden_dim = lstm_units * 2 #Nombre de dimensions du vecteur de sortie final
def abs_sub(x):
return K.abs(x[0] - x[1])
embedding = Embedding(input_dim=vocab_size, output_dim=embedding_dim)
input1 = Input(shape=(seq_length1,))
embed1 = embedding(input1)
bilstm1 = Bidirectional(LSTM(lstm_units, return_sequences=True), merge_mode='concat')(embed1)
h1 = Dropout(0.2)(bilstm1)
input2 = Input(shape=(seq_length2,))
embed2 = embedding(input2)
bilstm2 = Bidirectional(LSTM(lstm_units, return_sequences=True), merge_mode='concat')(embed2)
h2 = Dropout(0.2)(bilstm2)
#Calculez le produit pour chaque élément
product = dot([h2, h1], axes=2) #Taille:[Taille du lot, longueur de la réponse, longueur de la question]
a = Activation('softmax')(product)
c = dot([a, h1], axes=[2, 1])
c_h2 = concatenate([c, h2], axis=2)
h = Dense(hidden_dim, activation='tanh')(c_h2)
#Il est mis en œuvre ici.
mean_pooled_1 = AveragePooling1D(pool_size=seq_length1, strides=1, padding='valid')(h1)
mean_pooled_2 = AveragePooling1D(pool_size=seq_length2, strides=1, padding='valid')(h)
mean_pooled_1 = Reshape((lstm_units * 2,))(mean_pooled_1)
mean_pooled_2 = Reshape((lstm_units * 2,))(mean_pooled_2)
sub = Lambda(abs_sub)([mean_pooled_1, mean_pooled_2])
mult = multiply([mean_pooled_1, mean_pooled_2])
con = concatenate([mean_pooled_1, mean_pooled_2, sub, mult], axis=-1)
#con = Reshape((lstm_units * 2 * 4,))(con)
output = Dense(2, activation='softmax')(con)
model = Model(inputs=[input1, input2], outputs=output)
model.summary()
model.compile(optimizer="adam", loss="categorical_crossentropy")
Après avoir construit le modèle, nous allons apprendre le modèle.
Après avoir terminé tous les prétraitements sauf le remplissage et la conversion en ID On suppose qu'il est préparé dans ./nlp_data/.
Le dictionnaire de conversion des mots en ID est stocké dans ./nlp_data/word2id.json.
Le nom du fichier est ./nlp_data/preprocessed_train.json Les données d'évaluation sont ./nlp_data/preprocessed_val.json.
Les données de preprocessed_train.json ressemblent à ceci, par exemple.
{'answerChoices': {'a': [1082, 1181, 586, 2952, 0],
'b': [1471, 2492, 773, 0, 1297],
'c': [811, 2575, 0, 1181, 2841, 0],
'd': [2031, 1984, 1099, 0, 3345, 975, 87, 697, 1366]},
'correctAnswer': 'a',
'question': [544, 0]}
Cliquez ici pour des exemples d'utilisation
import json
import numpy as np
from keras.layers import Input, Dense, Dropout, Reshape
from keras.layers.embeddings import Embedding
from keras.layers.recurrent import LSTM
from keras.layers.wrappers import Bidirectional
from keras.layers.merge import dot, concatenate
from keras.layers.core import Activation
from keras.layers.pooling import AveragePooling1D
from keras.models import Model
from keras.preprocessing.sequence import pad_sequences
with open("./nlp_data/word2id.json", "r") as f:
word2id = json.load(f)
batch_size = 500 #Taille du lot
vocab_size = len(word2id) #Nombre de vocabulaire à gérer
embedding_dim = 100 #Dimensions du vecteur Word
seq_length1 = 20 #Longueur de la question
seq_length2 = 10 #Longueur de la réponse
lstm_units = 200 #Nombre de dimensions du vecteur d'état caché de LSTM
hidden_dim = 200 #Nombre de dimensions du vecteur de sortie final
embedding = Embedding(input_dim=vocab_size, output_dim=embedding_dim)
input1 = Input(shape=(seq_length1,))
embed1 = embedding(input1)
bilstm1 = Bidirectional(LSTM(lstm_units, return_sequences=True), merge_mode='concat')(embed1)
h1 = Dropout(0.2)(bilstm1)
input2 = Input(shape=(seq_length2,))
embed2 = embedding(input2)
bilstm2 = Bidirectional(LSTM(lstm_units, return_sequences=True), merge_mode='concat')(embed2)
h2 = Dropout(0.2)(bilstm2)
#Calculez le produit pour chaque élément
product = dot([h2, h1], axes=2) #Taille:[Taille du lot, longueur de la réponse, longueur de la question]
a = Activation('softmax')(product)
c = dot([a, h1], axes=[2, 1])
c_h2 = concatenate([c, h2], axis=2)
h = Dense(hidden_dim, activation='tanh')(c_h2)
mean_pooled_1 = AveragePooling1D(pool_size=seq_length1, strides=1, padding='valid')(h1)
mean_pooled_2 = AveragePooling1D(pool_size=seq_length2, strides=1, padding='valid')(h)
con = concatenate([mean_pooled_1, mean_pooled_2], axis=-1)
con = Reshape((lstm_units * 2 + hidden_dim,))(con)
output = Dense(2, activation='softmax')(con)
model = Model(inputs=[input1, input2], outputs=output)
model.compile(optimizer="adam", loss="categorical_crossentropy")
with open("./nlp_data/preprocessed_train.json", "r") as f:
train = json.load(f)
questions = []
answers = []
outputs = []
for t in train:
for i, ans in t["answerChoices"].items():
if i == t["correctAnswer"]:
outputs.append([1, 0])
else:
outputs.append([0, 1])
#Veuillez remplir le code ci-dessous
questions.append(t["question"])
answers.append(ans)
questions = pad_sequences(questions, maxlen=seq_length1, dtype=np.int32, padding='post', truncating='post', value=0)
answers = pad_sequences(answers, maxlen=seq_length2, dtype=np.int32, padding='post', truncating='post', value=0)
outputs = np.array(outputs)
#J'apprends
model.fit([questions[:10*100], answers[:10*100]], outputs[:10*100], batch_size=batch_size)
#Si vous travaillez localement, exécutez le code suivant.
# model.save_weights("./nlp_data/model.hdf5")
# model_json = model.to_json()
# with open("./nlp_data/model.json", "w") as f:
# json.dump(model_json, f)
Cliquez ici pour les résultats
Enfin, testez à l'aide des données d'évaluation.
Parce que c'est une classification binaire La précision est l'exactitude Précision Calculez le taux de rappel (Rappel).
Aussi, j'ai appris 5 époques ici Nous avons préparé un modèle entraîné ("./nlp_data/trained_model.hdf5").
Cliquez ici pour des exemples d'utilisation
import json
import numpy as np
from keras.models import model_from_json
from keras.preprocessing.sequence import pad_sequences
with open("./nlp_data/preprocessed_val.json", "r") as f:
val = json.load(f)
seq_length1 = 20 #Longueur de la question
seq_length2 = 10 #Longueur de la réponse
questions = []
answers = []
outputs = []
for t in val:
for i, ans in t["answerChoices"].items():
if i == t["correctAnswer"]:
outputs.append([1, 0])
else:
outputs.append([0, 1])
questions.append(t["question"])
answers.append(ans)
questions = pad_sequences(questions, maxlen=seq_length1, dtype=np.int32, padding='post', truncating='post', value=0)
answers = pad_sequences(answers, maxlen=seq_length2, dtype=np.int32, padding='post', truncating='post', value=0)
with open("./nlp_data/model.json", "r") as f:
model_json = json.load(f)
model = model_from_json(model_json)
model.load_weights("./nlp_data/trained_model.hdf5")
pred = model.predict([questions, answers])
pred_idx = np.argmax(pred, axis=-1)
true_idx = np.argmax(outputs, axis=-1)
TP = 0
FP = 0
FN = 0
TN = 0
for p, t in zip(pred_idx, true_idx):
if p == 0 and t == 0:
TP += 1
elif p == 0 and t == 1:
FP += 1
elif p == 1 and t == 0:
FN += 1
else:
TN += 1
print("Taux de réponse correct:", (TP+TN)/(TP+FP+FN+TN))
print("Taux de conformité:", TP/(TP+FP))
print("Rappel:", TP/(TP+FN))
Cliquez ici pour les résultats
L'attention est lors de l'application de l'attention de la phrase s à la phrase t
Quelle attention est accordée au j-ième mot de s au i-ième mot de t, comme dans On peut dire que aij le représente.
La matrice A qui a ce aij comme composant (i, j) est appelée la matrice d'attention. Vous pouvez visualiser la relation entre les mots s et t en consultant la matrice d'attention.
Les mots d'interrogation (axe horizontal) et les mots de réponse (axe vertical) qui sont étroitement liés sont affichés en blanc.
Cliquez ici pour des exemples d'utilisation
import matplotlib.pyplot as plt
import json
import numpy as np
from keras.layers import Input, Dense, Dropout, Reshape
from keras.layers.embeddings import Embedding
from keras.layers.recurrent import LSTM
from keras.layers.wrappers import Bidirectional
from keras.layers.merge import dot, concatenate
from keras.layers.core import Activation
from keras.layers.pooling import AveragePooling1D
from keras.models import Model
from keras.preprocessing.sequence import pad_sequences
from keras.models import model_from_json
import mpl_toolkits.axes_grid1
batch_size = 32 #Taille du lot
embedding_dim = 100 #Dimensions du vecteur Word
seq_length1 = 20 #Longueur de la question
seq_length2 = 10 #Longueur de la réponse
lstm_units = 200 #Nombre de dimensions du vecteur d'état caché de LSTM
hidden_dim = 200 #Nombre de dimensions du vecteur de sortie final
with open("./nlp_data/preprocessed_val.json", "r") as f:
val = json.load(f)
questions = []
answers = []
outputs = []
for t in val:
for i, ans in t["answerChoices"].items():
if i == t["correctAnswer"]:
outputs.append([1, 0])
else:
outputs.append([0, 1])
questions.append(t["question"])
answers.append(ans)
questions = pad_sequences(questions, maxlen=seq_length1,
dtype=np.int32, padding='post', truncating='post', value=0)
answers = pad_sequences(answers, maxlen=seq_length2,
dtype=np.int32, padding='post', truncating='post', value=0)
with open("./nlp_data/word2id.json", "r") as f:
word2id = json.load(f)
vocab_size = len(word2id) #Nombre de vocabulaire à gérer
embedding = Embedding(input_dim=vocab_size, output_dim=embedding_dim)
input1 = Input(shape=(seq_length1,))
embed1 = embedding(input1)
bilstm1 = Bidirectional(
LSTM(lstm_units, return_sequences=True), merge_mode='concat')(embed1)
h1 = Dropout(0.2)(bilstm1)
input2 = Input(shape=(seq_length2,))
embed2 = embedding(input2)
bilstm2 = Bidirectional(
LSTM(lstm_units, return_sequences=True), merge_mode='concat')(embed2)
h2 = Dropout(0.2)(bilstm2)
#Calculez le produit pour chaque élément
product = dot([h2, h1], axes=2) #Taille:[Taille du lot, longueur de la réponse, longueur de la question]
a = Activation('softmax')(product)
c = dot([a, h1], axes=[2, 1])
c_h2 = concatenate([c, h2], axis=2)
h = Dense(hidden_dim, activation='tanh')(c_h2)
mean_pooled_1 = AveragePooling1D(
pool_size=seq_length1, strides=1, padding='valid')(h1)
mean_pooled_2 = AveragePooling1D(
pool_size=seq_length2, strides=1, padding='valid')(h)
con = concatenate([mean_pooled_1, mean_pooled_2], axis=-1)
con = Reshape((lstm_units * 2 + hidden_dim,))(con)
output = Dense(2, activation='softmax')(con)
#Veuillez répondre ici
prob_model = Model(inputs=[input1, input2], outputs=[a, output])
prob_model.load_weights("./nlp_data/trained_model.hdf5")
question = np.array([[2945, 1752, 2993, 1099, 122, 2717, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])
answer = np.array([[2841, 830, 2433, 0, 0, 0, 0, 0, 0, 0]])
att, pred = prob_model.predict([question, answer])
id2word = {v: k for k, v in word2id.items()}
q_words = [id2word[w] for w in question[0]]
a_words = [id2word[w] for w in answer[0]]
f = plt.figure(figsize=(8, 8.5))
ax = f.add_subplot(1, 1, 1)
# add image
i = ax.imshow(att[0], interpolation='nearest', cmap='gray')
# add labels
ax.set_yticks(range(att.shape[1]))
ax.set_yticklabels(a_words)
ax.set_xticks(range(att.shape[2]))
ax.set_xticklabels(q_words, rotation=45)
ax.set_xlabel('Question')
ax.set_ylabel('Answer')
# add colorbar
divider = mpl_toolkits.axes_grid1.make_axes_locatable(ax)
cax = divider.append_axes('right', '5%', pad='3%')
plt.colorbar(i, cax=cax)
plt.show()
Cliquez ici pour les résultats
Recommended Posts