Trabajando con nuestro propio conjunto de datos con TorchText

TorchText puede leer tres formatos de datos: json, tsv (valores separados por tabuladores) y csv (valores separados por comas).

Manejo de datos JSON

Comenzando con json, tus datos deben estar en formato de línea json, es decir, debe ser así:

{
    
    "name": "John", "location": "United Kingdom", "age": 42, "quote": ["i", "love", "the", "united kingdom"]}
{
    
    "name": "Mary", "location": "United States", "age": 36, "quote": ["i", "want", "more", "telescopes"]}

Es decir, cada fila es un objeto json. datos/trian.json por ejemplo.

Luego definimos los campos:

from torchtext import data
from torchtext import datasets

NAME = data.Field()
SAYING = data.Field()
PLACE = data.Field()

A continuación, tenemos que decirle a TorchText qué campo se aplica a qué elemento del objeto json.

Para datos json tenemos que crear un diccionario:

  • key coincide con la clave del objeto json
  • El valor es una tupla, donde:
    • El primer elemento se convierte en el nombre de propiedad del objeto por lotes.
    • El segundo elemento es el nombre del campo.

Algunas notas:

  • El orden de las claves en el diccionario de campos no importa, siempre que sus claves coincidan con las claves de datos json.
  • Los nombres de campo no tienen que coincidir con las claves en el objeto json, por ejemplo, usamos LUGAR para el campo "ubicación".
  • Cuando se trata de datos json, no se deben usar todas las claves, por ejemplo, no usamos el campo "edad".
  • Del mismo modo, si el valor de un campo json es una cadena, se aplicará tokenización de campo (por defecto, la cadena está separada por espacios), sin embargo, si el valor es una lista, no se aplicará tokenización. Por lo general, es una buena idea tokenizar los datos como una lista, ahorra tiempo ya que no tiene que esperar a que TorchText lo haga.
  • Los valores de los campos json no tienen por qué ser del mismo tipo. Algunos ejemplos de "comillas" pueden ser cadenas, otros son listas. La tokenización solo se aplicará a las cadenas indicadas con "comillas".
  • Si está utilizando un campo json, cada instancia debe tener una instancia de ese campo, por ejemplo, en esta instancia, todas las instancias deben tener un nombre, una ubicación y una cita. Sin embargo, dado que no estamos usando el campo de edad, no importa que no haya un campo de edad en el ejemplo.
fields = {
    
    'name': ('n', NAME), 'location': ('p', PLACE), 'quote': ('s', SAYING)}

Ahora, en el ciclo de entrenamiento, podemos recorrer el iterador de datos y acceder al nombre a través de batch.n, a la ubicación a través de batch.p y a la cotización a través de batch.s.

Luego creamos nuestros conjuntos de datos (train_data y test_data) usando la función TabularDataset.splits

El parámetro de ruta especifica la carpeta de nivel superior común a ambos conjuntos de datos, y los parámetros de entrenamiento y prueba especifican el nombre de archivo de cada conjunto de datos, por ejemplo, el conjunto de datos de entrenamiento aquí se encuentra en data/train.json.

Le decimos a la función que estamos trabajando con datos json y le pasamos el diccionario de campos definido anteriormente.

train_data, test_data = data.TabularDataset.splits(
                            path = 'data',
                            train = 'train.json',
                            test = 'test.json',
                            format = 'json',
                            fields = fields
)

Si ya tiene un conjunto de datos de validación, puede pasar su ruta como parámetro de validación.

train_data, valid_data, test_data = data.TabularDataset.splits(
                                        path = 'data',
                                        train = 'train.json',
                                        validation = 'valid.json',
                                        test = 'test.json',
                                        format = 'json',
                                        fields = fields
)

Luego podemos ver un ejemplo para asegurarnos de que funciona correctamente.

Observe cómo los nombres de los campos (n, p y s) coinciden con lo que se define en el diccionario de campos.

Observe también cómo la palabra "Reino Unido" en p está separada por tokenización, mientras que "Reino Unido" en s no lo está. Esto es por las razones mencionadas anteriormente, TorchText asume que cualquier campo json que sea una lista ya ha sido tokenizado y no se aplica más tokenización.

print(vars(train_data[0]))
{
    
    'n': ['John'], 'p': ['United', 'Kingdom'], 's': ['i', 'love', 'the', 'united kingdom']}

Ahora podemos usar train_data, test_data y valid_data para construir el vocabulario y crear iteradores. Podemos usar batch.n, batch.p y batch.s para acceder a todos los atributos que representan nombres, lugares y dichos respectivamente.

Procesar datos CSV/TSV

csv y tsv son muy similares excepto que los elementos de csv están separados por comas, mientras que tsv está separado por tabuladores.

Usando el ejemplo anterior, nuestros datos tsv serían:

name    location    age quote
John    United Kingdom  42  i love the united kingdom
Mary    United States   36  i want more telescopes

Es decir, los elementos de cada línea están separados por tabuladores, con un ejemplo por línea. La primera fila suele ser los encabezados (es decir, los nombres de cada columna), pero es posible que sus datos tampoco tengan encabezados.

No puede tener listas en datos tsv o csv.

Los campos se definen de una manera ligeramente diferente a json. Ahora usamos una lista de tuplas, donde cada elemento es también una tupla. El primer elemento de estas tuplas internas serán los nombres de propiedad del objeto por lotes, y los segundos elementos son los nombres de campo.

A diferencia de los datos json, las tuplas deben estar en el mismo orden que en los datos tsv. Por lo tanto, al omitir una columna de datos, se debe usar una tupla de ninguno; de lo contrario, nuestro campo DECIR se aplicará a la columna de edad de los datos tsv y la columna de cotización no se usará.

Sin embargo, si solo desea usar las columnas de nombre y edad, puede usar las dos tuplas, ya que son las dos primeras columnas.

Cambiamos TabularDataset para leer el archivo .tsv correcto y cambiamos el parámetro de formato a 'tsv'.

Si sus datos tienen un encabezado, nuestros datos lo tienen, debe omitirse pasando skip_header=True. Si no, TorchText considerará la cabeza como ejemplo. De forma predeterminada, skip_header es falso.

fields = [('n', NAME), ('p', PLACE), (None, None), ('s', SAYING)]
train_data, valid_data, test_data = data.TabularDataset.splits(
                                        path = 'data',
                                        train = 'train.tsv',
                                        validation = 'valid.tsv',
                                        test = 'test.tsv',
                                        format = 'tsv',
                                        fields = fields,
                                        skip_header = True
)

print(vars(train_data[0]))
{
    
    'n': ['John'], 'p': ['United', 'Kingdom'], 's': ['i', 'love', 'the', 'united', 'kingdom']}

Finalmente, discutiremos los archivos csv.

Esto es casi idéntico a un archivo tsv, excepto que el parámetro de formato se establece en "csv".

fields = [('n', NAME), ('p', PLACE), (None, None), ('s', SAYING)]
train_data, valid_data, test_data = data.TabularDataset.splits(
                                        path = 'data',
                                        train = 'train.csv',
                                        validation = 'valid.csv',
                                        test = 'test.csv',
                                        format = 'csv',
                                        fields = fields,
                                        skip_header = True
)
print(vars(train_data[0]))
{
    
    'n': ['John'], 'p': ['United', 'Kingdom'], 's': ['i', 'love', 'the', 'united', 'kingdom']}

¿Por qué JSON es mejor que CSV/TSV?

  • Los datos csv o tsv no pueden almacenar listas. Esto significa que los datos no se pueden tokenizar, por lo que cada vez que se ejecuta un script de Python que lee datos a través de TorchText, los datos deben tokenizarse. El uso de tokenizadores avanzados, como el tokenizador spaCy, requiere una cantidad de tiempo no despreciable. Por lo tanto, es mejor etiquetar los conjuntos de datos y almacenarlos en formato de fila json.
  • Si aparecen tabulaciones en los datos tsv o aparecen comas en los datos csv, TorchText las considerará como separadores entre columnas. Esto hará que los datos se analicen incorrectamente. Lo peor de todo es que TorchText no le recordará esto porque no puede distinguir la diferencia entre una tabulación/coma en un campo y una tabulación/coma como delimitador. Dado que los datos json son esencialmente un diccionario y puede acceder a los datos en los campos mediante sus claves, no tiene que preocuparse por el delimitador "sorpresa".

iterador

Usando cualquiera de los conjuntos de datos anteriores, podemos construir el vocabulario y crear iteradores.

NAME.build_vocab(train_data)
SAYING.build_vocab(train_data)
PLACE.build_vocab(train_data)

Luego, después de definir el tamaño del lote y el dispositivo, podemos crear el iterador.

De forma predeterminada, los datos de entrenamiento se mezclan cada época, pero los datos de validación/prueba están ordenados. Sin embargo, TorchText no sabe qué usar para ordenar nuestros datos, y si no se lo decimos, arrojará un error.

Hay dos formas de manejar esto, puede decirle al iterador que no ordene los datos de validación/prueba pasando sort=False, o puede decirle al iterador cómo ordenar los datos pasando sort_key. sort key es una función que devuelve una clave utilizada para ordenar datos. Por ejemplo, lambda x: xs ordenará los ejemplos según su propiedad s (es decir, su cotización). Idealmente, desea utilizar la clave de ordenación, ya que BucketIterator podrá ordenar los ejemplos y luego minimizar la cantidad de relleno en cada lote.

Luego, podemos iterar sobre el iterador para obtener lotes de datos. Tenga en cuenta que, por defecto, la dimensión del lote de TorchText está en la segunda dimensión.

import torch

device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

BATCH_SIZE = 1

train_iterator, valid_iterator, test_iterator = data.BucketIterator.splits(
    (train_data, valid_data, test_data),
    sort = False, #don't sort test/validation data
    batch_size=BATCH_SIZE,
    device=device)

train_iterator, valid_iterator, test_iterator = data.BucketIterator.splits(
    (train_data, valid_data, test_data),
    sort_key = lambda x: x.s, #sort by s attribute (quote)
    batch_size=BATCH_SIZE,
    device=device)

print('Train:')
for batch in train_iterator:
    print(batch)
    
print('Valid:')
for batch in valid_iterator:
    print(batch)
    
print('Test:')
for batch in test_iterator:
    print(batch)

Train:

[torchtext.data.batch.Batch of size 1]
	[.n]:[torch.cuda.LongTensor of size 1x1 (GPU 0)]
	[.p]:[torch.cuda.LongTensor of size 2x1 (GPU 0)]
	[.s]:[torch.cuda.LongTensor of size 5x1 (GPU 0)]

[torchtext.data.batch.Batch of size 1]
	[.n]:[torch.cuda.LongTensor of size 1x1 (GPU 0)]
	[.p]:[torch.cuda.LongTensor of size 2x1 (GPU 0)]
	[.s]:[torch.cuda.LongTensor of size 4x1 (GPU 0)]
Valid:

[torchtext.data.batch.Batch of size 1]
	[.n]:[torch.cuda.LongTensor of size 1x1 (GPU 0)]
	[.p]:[torch.cuda.LongTensor of size 1x1 (GPU 0)]
	[.s]:[torch.cuda.LongTensor of size 2x1 (GPU 0)]

[torchtext.data.batch.Batch of size 1]
	[.n]:[torch.cuda.LongTensor of size 1x1 (GPU 0)]
	[.p]:[torch.cuda.LongTensor of size 1x1 (GPU 0)]
	[.s]:[torch.cuda.LongTensor of size 4x1 (GPU 0)]
Test:

[torchtext.data.batch.Batch of size 1]
	[.n]:[torch.cuda.LongTensor of size 1x1 (GPU 0)]
	[.p]:[torch.cuda.LongTensor of size 1x1 (GPU 0)]
	[.s]:[torch.cuda.LongTensor of size 3x1 (GPU 0)]

[torchtext.data.batch.Batch of size 1]
	[.n]:[torch.cuda.LongTensor of size 1x1 (GPU 0)]
	[.p]:[torch.cuda.LongTensor of size 2x1 (GPU 0)]
	[.s]:[torch.cuda.LongTensor of size 3x1 (GPU 0)]

Supongo que te gusta

Origin blog.csdn.net/weixin_40605573/article/details/113191026
Recomendado
Clasificación