Clasificación de texto de noticias PNL de entrada de base cero_Task4

A diferencia del aprendizaje automático tradicional, el aprendizaje profundo no solo proporciona funciones de extracción de características, sino también funciones de clasificación completas. Esta TAREA demuestra principalmente cómo utilizar el aprendizaje profundo para completar la representación del texto.
Este capítulo utiliza principalmente FastText para completar la representación de vectores de palabras de aprendizaje profundo. FastText asigna las palabras al espacio denso a través de la capa de incrustación y luego promedia todas las palabras de la oración en el espacio de la capa de incrustación para completar el trabajo de clasificación. Entonces, la capa FastText es una red neuronal de tres capas: capa de entrada, capa oculta y capa de salida.
Inserte la descripción de la imagen aquí
La siguiente figura es la estructura de red FastText implementada usando Keras. A
Inserte la descripción de la imagen aquí
continuación se muestra el código y la interpretación de la clasificación de texto de palabras completada por FastText, y el aprendizaje de FastText se completa a través de la reproducción del código.

Importar módulos de terceros

import pandas as pd
from sklearn.metrics import f1_score
from sklearn.model_selection import StratifiedKFold  # 这可以保证每一折分布一致
import fasttext

Use 'pip install fasttext' para informar un error aquí. La
solución es descargar primero el paquete de instalación de terceros de fasttext y luego especificar la ruta local para instalar.
Navegación del sitio web: https://www.lfd.uci.edu/~gohlke/pythonlibs/#fasttext
instalación Comando: pip install fasttext-0.9.2-cp38-cp38-win_amd64.whl (debe colocar el archivo de instalación en la ruta del entorno actual)

Modelo de clasificación

Para reducir la presión sobre la máquina, se importan 15.000 datos de muestra de entrenamiento

train_df = pd.read_csv(r'D:\Users\Felixteng\Documents\Pycharm Files\Nlp\data\train_set.csv',
                       sep='\t', nrows=15000)

Convierta al formato requerido por FastText. De forma predeterminada, asumimos que la etiqueta es una palabra con el prefijo __label__

train_df['label_ft'] = '__label__' + train_df['label'].astype(str)

Tome el texto y la nueva etiqueta de las primeras 10,000 muestras de capacitación para crear un nuevo conjunto de capacitación adecuado para el formato FastText

train_df[['text', 'label_ft']].iloc[:-5000].to_csv('train.csv', index=None, header=None, sep='\t')

Datos de entrenamiento, la tasa de aprendizaje se establece en 1, el número de n-gramos es 2 y se genera una fila de registros para cada época, el umbral de frecuencia de palabras es 1, el número de veces es 25 y la función de pérdida selecciona softmax jerárquico

model = fasttext.train_supervised('train.csv', lr=1.0, wordNgrams=2, verbose=2,
                                  minCount=1, epoch=25, loss='hs')
'''
fasttext.train_supervised() - 训练一个监督模型,返回一个模型对象
参数详解:
    input - 训练数据文件路径
    lr - 学习率
    dim - 向量维度
    ws - cbow模型时使用
    epoch - 次数
    minCount - 词频阈值,小于该值在初始化时会被过滤
    minCountLabel - 类别阈值,类别小于改值初始化时会被过滤
    minn - 构造subword时最小char个数
    maxn - 构造subword时最大char个数
    neg - 负采样
    wordNgrams - n-gram个数,组成词语的长度
    loss - 损失函数类型,softmax, ns:负采样, hs:分层softmax
    bucket - 词扩充大小,[A, B]:A语料中包含的词向量,B不在语料中的词向量
    thread - 线程个数,每个线程处理输入数据的一段,0号线程负责loss输出
    lrUpdateRate - 学习率更新
    t - 负采样阈值
    label - 类别前缀
    pretrainedVectors - 预训练的词向量文件路径,如果word出现在文件夹中初始化不再随机
    verbose - 日志显示
        verbose = 0 为不在标准输出流输出日志信息 
        verbose = 1 为输出进度条记录 
        verbose = 2 为每个epoch输出一行记录
'''

Predecir datos de validación y calcular la precisión

val_pred_fasttext = [model.predict(x)[0][0].split('__')[-1] for x in train_df.iloc[-5000:]['text']]
'''
由于FastText单个预测值返回的是一个元组,元组包括标签列表和概率列表,如:
    (('__label__4',), array([0.99362451]))
所以我们在提取预测类别值的时候提前加上切片操作,将词标签的值取出;
然后按照'__'对词标签进行分割,从而获取实际预测到的类别值

模型单例预测函数代码:
def model.predict(self, text, k=1, threshold=0.0):
  """
  模型预测,给定文本预测分类
  @param text:       字符串, 需要utf-8
  @param k:          返回标签的个数
  @param threshold   概率阈值, 大于该值才返回
  @return 标签列表, 概率列表
  """
  pass
'''

print(f1_score(train_df['label'].values[-5000:].astype(str), val_pred_fasttext, average='macro'))

f1_score es de aproximadamente 0,82.

Intente aumentar la cantidad de muestras de entrenamiento para mejorar su precisión

train_df_big = pd.read_csv(r'D:\Users\Felixteng\Documents\Pycharm Files\Nlp\data\train_set.csv',
                           sep='\t', nrows=75000)
train_df_big['label_ft'] = '__label__' + train_df_big['label'].astype(str)
train_df_big[['text', 'label_ft']].iloc[:50000].to_csv('train_big.csv', index=None, header=None, sep='\t')
model_big = fasttext.train_supervised('train_big.csv', lr=1.0, wordNgrams=2, verbose=2,
                                      minCount=1, epoch=25, loss='hs')
val_pred_fasttext_big = [model_big.predict(x)[0][0].split('__')[-1] for x in train_df_big.iloc[-50000:]['text']]
print(f1_score(train_df_big['label'].values[-50000:].astype(str), val_pred_fasttext_big, average='macro'))

La puntuación alcanzó 0,944.

10% de descuento en validación cruzada

Cada pliegue usa 9/10 de los datos para entrenamiento y 1/10 como verificación;
la división de cada pliegue debe asegurar que la distribución de la etiqueta sea consistente con la distribución de todo el conjunto de datos;
intente usar StratifiedKFold para dividir el conjunto de entrenamiento en 10 pliegues y guarde los diferentes pliegues por separado Conjunto de formación y conjunto de validación cuando se utiliza como conjunto de validación

train_df = pd.read_csv(r'D:\Users\Felixteng\Documents\Pycharm Files\Nlp\data\train_set.csv', sep='\t')
skf = StratifiedKFold(n_splits=10)  # 确保分出的折与原始集分布相同
for n_fold, (train_index, val_index) in enumerate(skf.split(train_df['text'], train_df['label'])):
    # enumerate()函数用于将一个可遍历的数据对象组合为一个索引序列,同时列出数据和数据下标,一般用在for循环当中
    print(f'the {n_fold} data split...')
    train_X, train_y, val_X, val_y = train_df['text'].iloc[train_index], train_df['label'][train_index], \
                                     train_df['text'].iloc[val_index], train_df['label'][val_index]
    # 把标签转化成FastText能训练的形式
    train_y = '__label__' + train_y.astype(str)
    train_data = pd.DataFrame(list(zip(train_X.values, train_y.values)))
    train_data.to_csv(f'data/fasttext_skf10_datasplit/train_split{n_fold}.csv',
                      index=None, header=['text', 'label_ft'], sep='\t')
    test_data = pd.DataFrame(list(zip(val_X.values, val_y.values)))
    test_data.to_csv(f'data/fasttext_skf10_datasplit/test_split{n_fold}.csv',
                     index=None, header=['text', 'label'], sep='\t')

Utilice una validación cruzada de 10 veces para ajustar los parámetros

print('starting K10 cross-validation training:')
# val_f1用于存放10次验证集的f1_score
val_f1 = []
for n_fold in range(10):
    model = fasttext.train_supervised(f'data/fasttext_skf10_datasplit/train_split{n_fold}.csv',
                                      lr=1.0, wordNgrams=2, verbose=2, minCount=1, epoch=25, loss='softmax')
    val_df = pd.read_csv(f'data/fasttext_skf10_datasplit/test_split{n_fold}.csv', sep='\t')
    val_pred = [model.predict(x)[0][0].split('__')[-1] for x in val_df['text']]
    val_f1.append(f1_score(val_df['label'].values.astype(str), val_pred, average='macro'))
    print(f'the f1_score of {n_fold}training is:', val_f1[n_fold])
print('The average f1_score is:', sum(val_f1) / len(val_f1))

Después de un largo entrenamiento y espera ...
Inserte la descripción de la imagen aquí
la puntuación de diez entrenamientos es de 0,93, que no está nada mal.

Verificación en línea

test_data = pd.read_csv(r'D:\Users\Felixteng\Documents\Pycharm Files\Nlp\data\test_a.csv', sep='\t')
test_pred = [model.predict(x)[0][0].split('__')[-1] for x in test_data['text']]
sub = pd.DataFrame(test_pred, columns=['label'])
sub.to_csv('sub.csv', index=False)

La puntuación del resultado de la predicción online es 0.9304, la diferencia entre online y offline no es grande, la puntuación no es mala, pero los parámetros no han cambiado mucho y hay margen de mejora.

Traté de ajustar manualmente los parámetros varias veces antes y después, pero la puntuación no aumentó

val_0 = pd.read_csv(f'data/fasttext_skf10_datasplit/test_split0.csv', sep='\t')
model_0 = fasttext.train_supervised(f'data/fasttext_skf10_datasplit/train_split0.csv',
                                    lr=1.0, wordNgrams=3, verbose=2, minCount=1, epoch=25, loss='softmax')
val_pred_0 = [model_0.predict(x)[0][0].split('__')[-1] for x in val_0['text']]
print(f1_score(val_0['label'].values.astype(str), val_pred_0, average='macro'))

test_pred_0 = [model_0.predict(x)[0][0].split('__')[-1] for x in test_data['text']]
sub_0 = pd.DataFrame(test_pred_0, columns=['label'])
sub_0.to_csv('sub_0.csv', index=False)


val_1 = pd.read_csv(f'data/fasttext_skf10_datasplit/test_split1.csv', sep='\t')
model_1 = fasttext.train_supervised(f'data/fasttext_skf10_datasplit/train_split1.csv',
                                    lr=1.5, wordNgrams=3, verbose=2, minCount=1, epoch=25, loss='softmax')
val_pred_1 = [model_1.predict(x)[0][0].split('__')[-1] for x in val_1['text']]
print(f1_score(val_1['label'].values.astype(str), val_pred_1, average='macro'))
'''
0.9344292030486819
'''


val_2 = pd.read_csv(f'data/fasttext_skf10_datasplit/test_split2.csv', sep='\t')
model_2 = fasttext.train_supervised(f'data/fasttext_skf10_datasplit/train_split2.csv',
                                    lr=2, wordNgrams=3, verbose=2, minCount=1, epoch=25, loss='softmax')
val_pred_2 = [model_2.predict(x)[0][0].split('__')[-1] for x in val_2['text']]
print(f1_score(val_2['label'].values.astype(str), val_pred_2, average='macro'))
'''
0.934281492108054
'''


val_3 = pd.read_csv(f'data/fasttext_skf10_datasplit/test_split3.csv', sep='\t')
model_3 = fasttext.train_supervised(f'data/fasttext_skf10_datasplit/train_split3.csv',
                                    lr=1.5, wordNgrams=4, verbose=2, minCount=1, epoch=25, loss='softmax')
val_pred_3 = [model_3.predict(x)[0][0].split('__')[-1] for x in val_3['text']]
print(f1_score(val_3['label'].values.astype(str), val_pred_3, average='macro'))
'''
0.9383561689755379
'''


val_4 = pd.read_csv(f'data/fasttext_skf10_datasplit/test_split4.csv', sep='\t')
model_4 = fasttext.train_supervised(f'data/fasttext_skf10_datasplit/train_split4.csv',
                                    lr=2.5, wordNgrams=3, verbose=2, minCount=1, epoch=25, loss='softmax')
val_pred_4 = [model_4.predict(x)[0][0].split('__')[-1] for x in val_4['text']]
print(f1_score(val_4['label'].values.astype(str), val_pred_4, average='macro'))
'''
0.9353875257235135
'''


val_5 = pd.read_csv(f'data/fasttext_skf10_datasplit/test_split5.csv', sep='\t')
model_5 = fasttext.train_supervised(f'data/fasttext_skf10_datasplit/train_split5.csv',
                                    lr=2, wordNgrams=4, verbose=2, minCount=1, epoch=30, loss='softmax')
val_pred_5 = [model_5.predict(x)[0][0].split('__')[-1] for x in val_5['text']]
print(f1_score(val_5['label'].values.astype(str), val_pred_5, average='macro'))
'''
0.9354738839095721
'''


test_pred_3 = [model_3.predict(x)[0][0].split('__')[-1] for x in test_data['text']]
sub_3 = pd.DataFrame(test_pred_3, columns=['label'])
sub_3.to_csv('sub_3.csv', index=False)

Todas las puntuaciones rondan el 0,935. Además de escribir un script de ajuste automático de parámetros, es posible que se necesite un modelo de mayor precisión para el entrenamiento.

En el próximo capítulo, continuaremos probando tareas de clasificación de texto con otros modelos de aprendizaje profundo.

Supongo que te gusta

Origin blog.csdn.net/Baby1601tree/article/details/107594365
Recomendado
Clasificación