Encodage des données
Introduction et notation
Pour utiliser un algorithme quantique, les données classiques doivent d'une façon ou d'une autre être introduites dans un circuit quantique. On parle généralement d'encodage des données, mais aussi de chargement des données. Rappelle-toi des leçons précédentes la notion de mapping de caractéristiques (feature mapping), c'est-à-dire un mapping des caractéristiques des données d'un espace vers un autre. Le simple transfert de données classiques vers un ordinateur quantique est une sorte de mapping, et pourrait être appelé un feature mapping. En pratique, les feature mappings intégrés dans Qiskit (comme z_Feature Map et ZZ Feature Map) incluent généralement des couches de rotation et des couches d'intrication qui étendent l'état à de nombreuses dimensions dans l'espace de Hilbert. Ce processus d'encodage est une partie critique des algorithmes d'apprentissage automatique quantique et affecte directement leurs capacités computationnelles.
Certaines des techniques d'encodage présentées ci-dessous peuvent être simulées de façon efficace sur un ordinateur classique ; c'est particulièrement facile à voir dans les méthodes d'encodage qui produisent des états produits (c'est-à-dire qu'elles n'intriquent pas les qubits). Et rappelle-toi que l'utilité quantique réside très probablement là où la complexité quantique du jeu de données est bien adaptée à la méthode d'encodage. Il est donc très probable que tu finisses par écrire tes propres circuits d'encodage. Ici, nous présentons une grande variété de stratégies d'encodage possibles, simplement pour que tu puisses les comparer et les mettre en contraste, et voir ce qui est possible. On peut formuler quelques affirmations très générales sur l'utilité des techniques d'encodage. Par exemple, efficient_su2 (voir ci-dessous) avec un schéma d'intrication complet est bien plus susceptible de capturer les caractéristiques quantiques des données que les méthodes qui produisent des états produits (comme z_feature_map). Mais cela ne signifie pas qu'efficient_su2 est suffisant, ou suffisamment bien adapté à ton jeu de données, pour produire une accélération quantique. Cela nécessite une réflexion approfondie sur la structure des données à modéliser ou à classer. Il y a aussi un équilibre à trouver avec la profondeur des circuits, car de nombreux feature maps qui intriquent entièrement les qubits dans un circuit produisent des circuits très profonds, trop profonds pour obtenir des résultats utilisables sur les ordinateurs quantiques actuels.
Notation
Un jeu de données est un ensemble de vecteurs de données : , où chaque vecteur est de dimension , c'est-à-dire . Cela pourrait être étendu à des caractéristiques de données complexes. Dans cette leçon, nous pourrons utiliser occasionnellement ces notations pour l'ensemble complet et ses éléments spécifiques comme . Mais nous nous référerons principalement au chargement d'un seul vecteur de notre jeu de données à la fois, et nous nous référerons souvent simplement à un seul vecteur de caractéristiques comme .
De plus, il est courant d'utiliser le symbole pour désigner le feature mapping du vecteur de données . En informatique quantique spécifiquement, il est courant de désigner les mappings quantiques par une notation qui renforce la nature unitaire de ces opérations. On pourrait correctement utiliser le même symbole pour les deux ; ce sont tous les deux des feature mappings. Tout au long de ce cours, nous utilisons :
- quand nous discutons des feature mappings en apprentissage automatique, de façon générale, et
- quand nous discutons des implémentations en circuits des feature mappings.
Normalisation et perte d'information
En apprentissage automatique classique, les caractéristiques des données d'entraînement sont souvent « normalisées » ou redimensionnées, ce qui améliore souvent les performances du modèle. Une façon courante de le faire est d'utiliser la normalisation min-max ou la standardisation. Dans la normalisation min-max, les colonnes de caractéristiques de la matrice de données (disons, la caractéristique ) sont normalisées :
où min et max désignent le minimum et le maximum de la caractéristique sur les vecteurs de données du jeu de données . Toutes les valeurs de caractéristiques tombent alors dans l'intervalle unité : pour tout , .
La normalisation est aussi un concept fondamental en mécanique quantique et en informatique quantique, mais elle est légèrement différente de la normalisation min-max. La normalisation en mécanique quantique exige que la longueur (dans le contexte de l'informatique quantique, la 2-norme) d'un vecteur d'état soit égale à l'unité : , garantissant que les probabilités de mesure somment à 1. L'état est normalisé en divisant par la 2-norme ; c'est-à-dire en redimensionnant
En informatique quantique et en mécanique quantique, il ne s'agit pas d'une normalisation imposée par les gens sur les données, mais d'une propriété fondamentale des états quantiques. Selon ton schéma d'encodage, cette contrainte peut affecter la façon dont tes données sont redimensionnées. Par exemple, dans l'encodage en amplitude (voir ci-dessous), le vecteur de données est normalisé comme l'exige la mécanique quantique, et cela affecte le redimensionnement des données encodées. Dans l'encodage en phase, il est recommandé de redimensionner les valeurs des caractéristiques comme afin d'éviter toute perte d'information due à l'effet modulo- de l'encodage vers un angle de phase de qubit[1,2].
Méthodes d'encodage
Dans les prochaines sections, nous nous référerons à un petit exemple de jeu de données classique composé de vecteurs de données, chacun avec caractéristiques :
Dans la notation introduite ci-dessus, on pourrait dire que la caractéristique du vecteur de données de notre ensemble est par exemple.
Encodage en base
L'encodage en base encode une chaîne de bits classique dans un état de base computationnel d'un système à qubits. Prenons par exemple Cela peut être représenté comme une chaîne de bits , et par un système à qubits comme l'état quantique . Plus généralement, pour une chaîne de bits : , l'état à qubits correspondant est avec pour . Note que cela concerne une seule caractéristique.
L'encodage en base en informatique quantique représente chaque bit classique comme un qubit séparé, mappant la représentation binaire des données directement sur des états quantiques dans la base computationnelle. Lorsque plusieurs caractéristiques doivent être encodées, chaque caractéristique est d'abord convertie en sa forme binaire, puis assignée à un groupe distinct de qubits — un groupe par caractéristique — où chaque qubit reflète un bit dans la représentation binaire de cette caractéristique.
À titre d'exemple, encodons le vecteur (5, 7, 0).
Supposons que toutes les caractéristiques sont stockées sur quatre bits (plus que nécessaire, mais suffisant pour représenter tout entier à un chiffre en base 10) :
5 → binaire 0101
7 → binaire 0111
0 → binaire 0000
Ces chaînes de bits sont assignées à trois ensembles de quatre qubits, de sorte que l'état de base global à 12 qubits est :
Ici, les quatre premiers qubits représentent la première caractéristique, les quatre qubits suivants la deuxième caractéristique, et les quatre derniers qubits la troisième caractéristique. Le code ci-dessous convertit le vecteur de données (5,7,0) en un état quantique, et est généralisé pour le faire pour d'autres caractéristiques à un seul chiffre.
# Added by doQumentation — required packages for this notebook
!pip install -q matplotlib numpy qiskit
from qiskit import QuantumCircuit
# Data point to encode
x = 5 # binary: 0101
y = 7 # binary: 0111
z = 0 # binary: 0000
# Convert each to 4-bit binary list
x_bits = [int(b) for b in format(x, "04b")] # [0,1,0,1]
y_bits = [int(b) for b in format(y, "04b")] # [0,1,1,1]
z_bits = [int(b) for b in format(z, "04b")] # [0,0,0,0]
# Combine all bits
all_bits = x_bits + y_bits + z_bits # [0,1,0,1,0,1,1,1,0,0,0,0]
# Initialize a 12-qubit quantum circuit
qc = QuantumCircuit(12)
# Apply x-gates where the bit is 1
for idx, bit in enumerate(all_bits):
if bit == 1:
qc.x(idx)
qc.draw("mpl")

Vérifie ta compréhension
Lis la question ci-dessous, réfléchis à ta réponse, puis clique sur le triangle pour révéler la solution.
Écris du code pour encoder le premier vecteur de notre exemple de jeu de données :
en utilisant l'encodage en base.
Réponse :
import math
from qiskit import QuantumCircuit
# Data point to encode
x = 4 # binary: 0100
y = 8 # binary: 1000
z = 5 # binary: 0101
# Convert each to 4-bit binary list
x_bits = [int(b) for b in format(x, '04b')] # [0,1,0,0]
y_bits = [int(b) for b in format(y, '04b')] # [1,0,0,0]
z_bits = [int(b) for b in format(z, '04b')] # [0,1,0,1]
# Combine all bits
all_bits = x_bits + y_bits + z_bits # [0,1,0,0,1,0,0,0,0,1,0,1]
# Initialize a 12-qubit quantum circuit
qc = QuantumCircuit(12)
# Apply x-gates where the bit is 1
for idx, bit in enumerate(all_bits):
if bit == 1:
qc.x(idx)
qc.draw('mpl')
Encodage en amplitude
L'encodage en amplitude encode les données dans les amplitudes d'un état quantique. Il représente un vecteur de données classique normalisé de dimension , , comme les amplitudes d'un état quantique à qubits, :
où est la même dimension des vecteurs de données qu'auparavant, est le élément de et est le état de base computationnel. Ici, est une constante de normalisation à déterminer à partir des données encodées. C'est la condition de normalisation imposée par la mécanique quantique :
En général, il s'agit d'une condition différente de la normalisation min/max utilisée pour chaque caractéristique sur l'ensemble des vecteurs de données. La façon dont cela est géré dépendra de ton problème. Mais il n'y a pas moyen de contourner la condition de normalisation de la mécanique quantique ci-dessus.
Dans l'encodage en amplitude, chaque caractéristique d'un vecteur de données est stockée comme une amplitude d'un état quantique différent. Comme un système de qubits fournit amplitudes, l'encodage en amplitude de caractéristiques nécessite qubits.
À titre d'exemple, encodons le premier vecteur de notre exemple de jeu de données , en utilisant l'encodage en amplitude. En normalisant le vecteur résultant, on obtient :
et l'état quantique à 2 qubits résultant serait :
Dans l'exemple ci-dessus, le nombre de caractéristiques dans le vecteur n'est pas une puissance de 2. Lorsque n'est pas une puissance de 2, on choisit simplement une valeur pour le nombre de qubits telle que et on complète le vecteur d'amplitudes avec des constantes non informatives (ici, un zéro).
Comme pour l'encodage en base, une fois qu'on a calculé quel état encodera notre jeu de données, dans Qiskit on peut utiliser la fonction initialize pour le préparer :
import math
desired_state = [
1 / math.sqrt(105) * 4,
1 / math.sqrt(105) * 8,
1 / math.sqrt(105) * 5,
1 / math.sqrt(105) * 0,
]
qc = QuantumCircuit(2)
qc.initialize(desired_state, [0, 1])
qc.decompose(reps=5).draw(output="mpl")
Un avantage de l'encodage en amplitude est la nécessité mentionnée ci-dessus de seulement qubits pour encoder. Cependant, les algorithmes ultérieurs doivent opérer sur les amplitudes d'un état quantique, et les méthodes pour préparer et mesurer les états quantiques ont tendance à ne pas être efficaces.
Vérifie ta compréhension
Lis les questions ci-dessous, réfléchis à tes réponses, puis clique sur les triangles pour révéler les solutions.
Écris l'état normalisé pour encoder le vecteur suivant (composé de deux vecteurs de notre exemple de jeu de données) :
en utilisant l'encodage en amplitude.
Réponse :
Pour encoder 6 nombres, nous aurons besoin d'au moins 6 états disponibles sur les amplitudes desquels nous pouvons encoder. Cela nécessitera 3 qubits. En utilisant un facteur de normalisation inconnu , on peut écrire cela comme :
Note que
Donc finalement,
Pour le même vecteur de données écris du code pour créer un circuit qui charge ces caractéristiques de données en utilisant l'encodage en amplitude.
Réponse :
desired_state = [
9 / math.sqrt(270),
8 / math.sqrt(270),
6 / math.sqrt(270),
2 / math.sqrt(270),
9 / math.sqrt(270),
2 / math.sqrt(270),
0,
0,
]
print(desired_state)
qc = QuantumCircuit(3)
qc.initialize(desired_state, [0, 1, 2])
qc.decompose(reps=8).draw(output="mpl")
[0.5477225575051662, 0.48686449556014766, 0.36514837167011077, 0.12171612389003691, 0.5477225575051662, 0.12171612389003691, 0, 0]
Tu pourrais avoir besoin de traiter de très grands vecteurs de données. Considère le vecteur
Écris du code pour automatiser la normalisation et générer un circuit quantique pour l'encodage en amplitude.
Réponse :
Il y a de nombreuses réponses possibles. Voici du code qui affiche quelques étapes intermédiaires :
import numpy as np
from math import sqrt
init_list = [4, 8, 5, 9, 8, 6, 2, 9, 2, 5, 7, 0, 3, 7, 5]
qubits = round(np.log(len(init_list)) / np.log(2) + 0.4999999999)
need_length = 2**qubits
pad = need_length - len(init_list)
for i in range(0, pad):
init_list.append(0)
init_array = np.array(init_list) # Unnormalized data vector
length = sqrt(
sum(init_array[i] ** 2 for i in range(0, len(init_array)))
) # Vector length
norm_array = init_array / length # Normalized array
print("Normalized array:")
print(norm_array)
print()
qubit_numbers = []
for i in range(0, qubits):
qubit_numbers.append(i)
print(qubit_numbers)
qc = QuantumCircuit(qubits)
qc.initialize(norm_array, qubit_numbers)
qc.decompose(reps=7).draw(output="mpl")
Normalized array: [0.17342199 0.34684399 0.21677749 0.39019949 0.34684399 0.26013299 0.086711 0.39019949 0.086711 0.21677749 0.30348849 0. 0.1300665 0.30348849 0.21677749 0. ]
[0, 1, 2, 3]

Vois-tu des avantages à l'encodage en amplitude par rapport à l'encodage en base ? Si oui, explique.
Réponse :
Il peut y avoir plusieurs réponses. Une réponse est que, étant donné l'ordre fixe des états de base, cet encodage en amplitude préserve l'ordre des nombres encodés. Il sera souvent aussi encodé de façon plus dense.
Un avantage de l'encodage en amplitude est qu'il faut seulement qubits pour un vecteur de données à dimensions ( caractéristiques) . Cependant, l'encodage en amplitude est généralement une procédure inefficace qui nécessite une préparation d'état arbitraire, qui est exponentielle dans le nombre de portes CNOT. Autrement dit, la préparation d'état a une complexité de calcul polynomiale de en nombre de dimensions, où , et est le nombre de qubits. L'encodage en amplitude « fournit une économie exponentielle en espace au prix d'une augmentation exponentielle en temps »[3] ; cependant, des augmentations de temps de calcul à sont réalisables dans certains cas[4]. Pour une accélération quantique de bout en bout, la complexité du temps de calcul du chargement des données doit être prise en compte.
Encodage en angle
L'encodage en angle est intéressant dans de nombreux modèles QML utilisant des feature maps de Pauli comme les machines à vecteurs de support quantiques (QSVM) et les circuits quantiques variationnels (VQC), entre autres. L'encodage en angle est étroitement lié à l'encodage en phase et à l'encodage en angle dense qui sont présentés ci-dessous. Ici, nous utiliserons « encodage en angle » pour désigner une rotation en , c'est-à-dire une rotation hors de l'axe accomplie par exemple par une porte ou une porte [1,3]. En réalité, on peut encoder des données dans n'importe quelle rotation ou combinaison de rotations. Mais est courant dans la littérature, donc nous l'accentuons ici.
Lorsqu'elle est appliquée à un seul qubit, l'encodage en angle imprime une rotation autour de l'axe Y proportionnelle à la valeur des données. Considère l'encodage d'une seule caractéristique () du vecteur de données d'un jeu de données, :