Comment créer un IA-raciste sans trop d'effort

Une leçon d'avertissement.

Faisons un classificateur de tonalité!

L'analyse des sentiments (analyse des sentiments) est une tâche très courante dans le traitement du langage naturel (PNL), et cela n'est pas surprenant. Il est important pour une entreprise de comprendre ce que les gens disent: positif ou négatif. Une telle analyse est utilisée pour surveiller les réseaux sociaux, les commentaires des clients et même dans le trading boursier algorithmique (en conséquence, les bots achètent des actions Berkshire Hathaway après avoir publié des critiques positives sur le rôle d'Anne Hathaway dans le dernier film ).

La méthode d'analyse est parfois trop simplifiée, mais c'est l'un des moyens les plus simples d'obtenir des résultats mesurables. Soumettez simplement le texte - et le résultat est positif et négatif. Pas besoin de traiter l'arbre d'analyse, de construire un graphique ou une autre représentation complexe.

Voilà ce que nous allons faire. Nous suivrons la voie de la moindre résistance et ferons le classificateur le plus simple, qui semble probablement très familier à tous ceux qui sont impliqués dans des développements pertinents dans le domaine de la PNL. Par exemple, un tel modèle peut être trouvé dans l'article Deep Averaging Networks (Iyyer et al., 2015). Nous n'essayons pas du tout de contester leurs résultats ou de critiquer le modèle; nous donnons simplement une méthode bien connue de représentation vectorielle des mots.

Plan de travail:

  • Introduire une représentation vectorielle typique des mots pour travailler avec des significations (significations).
  • Introduisez des ensembles de données de formation et de test avec des listes standard de mots positifs et négatifs.
  • Entraînez le classificateur de descente de gradient à reconnaître d'autres mots positifs et négatifs en fonction de leur représentation vectorielle.
  • Utilisez ce classificateur pour calculer les notes de tonalité des phrases de texte.
  • Pour voir le monstre que nous avons créé.

Et puis nous verrons, "comment créer un IA-raciste sans efforts particuliers." Bien sûr, vous ne pouvez pas laisser le système sous une forme aussi monstrueuse, alors nous allons:

  • Évaluer le problème statistiquement, afin qu'il devienne possible de mesurer les progrès au fur et à mesure qu'il est résolu.
  • Améliorez les données pour obtenir un modèle sémantique plus précis et moins raciste.

Dépendances logicielles


Ce didacticiel est écrit en Python et repose sur une pile d'apprentissage machine Python typique: numpy et scipy pour l'informatique numérique, pandas pour la gestion des données et scikit-learn pour l'apprentissage machine. Au final, nous seaborn également matplotlib et seaborn pour construire des diagrammes.

En principe, scikit-learn peut être remplacé par TensorFlow ou Keras, ou quelque chose comme ça: ils sont également capables de former le classifieur en descente de gradient. Mais nous n'avons pas besoin de leurs abstractions, car ici la formation se déroule en une seule étape.

 import numpy as np import pandas as pd import matplotlib import seaborn import re import statsmodels.formula.api from sklearn.linear_model import SGDClassifier from sklearn.model_selection import train_test_split from sklearn.metrics import accuracy_score #     %matplotlib inline seaborn.set_context('notebook', rc={'figure.figsize': (10, 6)}, font_scale=1.5) 

Étape 1. Représentation vectorielle des mots


Les représentations vectorielles sont souvent utilisées en cas de saisie de texte. Les mots deviennent des vecteurs dans un espace multidimensionnel, où les vecteurs adjacents représentent des significations similaires. En utilisant des représentations vectorielles, vous pouvez comparer les mots par (grossièrement) leur signification, et pas seulement par des correspondances exactes.

Un apprentissage réussi nécessite des centaines de gigaoctets de texte. Heureusement, diverses équipes de recherche ont déjà effectué ce travail et fourni des modèles pré-formés de représentations vectorielles disponibles en téléchargement.

Les deux ensembles de données les plus connus pour la langue anglaise sont word2vec (formé sur les textes de Google News) et GloVe (sur les pages Web Common Crawl). Chacun d'eux donnera un résultat similaire, mais nous prendrons le modèle GloVe car il a une source de données plus transparente.

GloVe est disponible en trois tailles: 6 milliards, 42 milliards et 840 milliards. Le dernier modèle est le plus puissant, mais nécessite des ressources de traitement importantes. La version de 42 milliards est assez bonne, et le dictionnaire est soigneusement coupé à 1 million de mots. Nous sommes sur le chemin de la moindre résistance, alors prenez la version 42 milliards.

- Pourquoi est-il si important d'utiliser un modèle «bien connu»?

"Je suis content que vous ayez posé des questions à ce sujet, hypothétique interlocuteur!" À chaque étape, nous essayons de faire quelque chose d'extrêmement typique, et le meilleur modèle pour la représentation vectorielle des mots pour une raison quelconque n'a pas encore été déterminé. J'espère que cet article suscitera le désir d'utiliser des modèles modernes de haute qualité , en particulier ceux qui prennent en compte une erreur algorithmique et tentent de la corriger. Cependant, plus à ce sujet plus tard.

Téléchargez glove.42B.300d.zip depuis le site Web de GloVe et extrayez le fichier data/glove.42B.300d.txt . Ensuite, nous définissons une fonction de lecture des vecteurs dans un format simple.

 def load_embeddings(filename): """  DataFrame      ,   word2vec, GloVe, fastText  ConceptNet Numberbatch.            . """ labels = [] rows = [] with open(filename, encoding='utf-8') as infile: for i, line in enumerate(infile): items = line.rstrip().split(' ') if len(items) == 2: # This is a header row giving the shape of the matrix continue labels.append(items[0]) values = np.array([float(x) for x in items[1:]], 'f') rows.append(values) arr = np.vstack(rows) return pd.DataFrame(arr, index=labels, dtype='f') embeddings = load_embeddings('data/glove.42B.300d.txt') embeddings.shape 

(1917494, 300)

Étape 2. Dictionnaire de tonalité standard d'or


Maintenant, nous avons besoin d'informations sur les mots considérés comme positifs et ceux qui sont négatifs. Il existe de nombreux dictionnaires de ce type, mais nous prendrons un dictionnaire très simple (Hu et Liu, 2004), qui est utilisé dans l'article de Deep Averaging Networks .

Téléchargez le dictionnaire depuis le site Web de Bing Liu et extrayez les données dans data/positive-words.txt et data/negative-words.txt .

Ensuite, nous déterminons comment lire ces fichiers et les affecter en tant que neg_words pos_words et neg_words :

 def load_lexicon(filename): """       (https://www.cs.uic.edu/~liub/FBS/sentiment-analysis.html)      Latin-1.      ,    - .    ,    ';'   ,   . """ lexicon = [] with open(filename, encoding='latin-1') as infile: for line in infile: line = line.rstrip() if line and not line.startswith(';'): lexicon.append(line) return lexicon pos_words = load_lexicon('data/positive-words.txt') neg_words = load_lexicon('data/negative-words.txt') 

Étape 3. Nous formons le modèle pour prédire la tonalité


Sur la base des vecteurs de mots positifs et négatifs, nous utilisons la commande Pandas .loc[] pour rechercher des représentations vectorielles de tous les mots.

Certains mots manquent dans le dictionnaire GloVe. Le plus souvent, ce sont des fautes de frappe comme «fanciner». Ici, nous voyons un tas de NaN , qui indique l'absence d'un vecteur, et supprimez-les avec la commande .dropna() .

pos_vectors = embeddings.loc[pos_words].dropna()
neg_vectors = embeddings.loc[neg_words].dropna()


Nous créons maintenant des tableaux de données en entrée (représentations vectorielles) et en sortie (1 pour les mots positifs et -1 pour les négatifs). Nous vérifions également que les vecteurs sont attachés aux mots afin de pouvoir interpréter les résultats.

vectors = pd.concat([pos_vectors, neg_vectors])
targets = np.array([1 for entry in pos_vectors.index] + [-1 for entry in neg_vectors.index])
labels = list(pos_vectors.index) + list(neg_vectors.index)


- Attends. Certains mots ne sont ni positifs ni négatifs, ils sont neutres. Ne faut-il pas créer une troisième classe pour les mots neutres?

"Je pense qu'il aurait été utile." Plus tard, nous verrons quels problèmes surviennent en raison de l'attribution de la tonalité aux mots neutres. Si nous pouvons identifier de manière fiable des mots neutres, alors il est tout à fait possible d'augmenter la complexité du classificateur à trois catégories. Mais vous devez trouver un dictionnaire de mots neutres, car dans le dictionnaire de Liu, il n'y a que des mots positifs et négatifs.

J'ai donc essayé ma version avec 800 exemples de mots et augmenté le poids pour prédire les mots neutres. Mais les résultats finaux n'étaient pas très différents de ce que vous verrez maintenant.

- Comment cette liste distingue-t-elle les mots positifs et négatifs? Cela ne dépend-il pas du contexte?

- Bonne question. L'analyse des clés générales n'est pas aussi simple qu'il y paraît. La frontière est assez arbitraire à certains endroits. Dans cette liste, le mot «impudent» est marqué comme «mauvais» et «ambitieux» comme «bon». «Bande dessinée» est mauvais et «drôle» est bon. Un «remboursement» est bon, bien qu'il soit généralement mentionné dans un mauvais contexte lorsque vous devez de l'argent à quelqu'un ou que vous le devez.

Tout le monde comprend que la tonalité est déterminée par le contexte, mais dans un modèle simple, vous devez ignorer le contexte et espérer que la tonalité moyenne sera devinée correctement.

En utilisant la fonction train_test_split , train_test_split divisons simultanément les vecteurs d'entrée, les valeurs de sortie et les étiquettes en données d'apprentissage et de test, tout en laissant 10% pour les tests.

 train_vectors, test_vectors, train_targets, test_targets, train_labels, test_labels = \ train_test_split(vectors, targets, labels, test_size=0.1, random_state=0) 

Créez maintenant un classificateur et passez des vecteurs à travers les itérations. Nous utilisons la fonction de perte logistique pour que le classificateur final puisse déduire la probabilité que le mot soit positif ou négatif.

 model = SGDClassifier(loss='log', random_state=0, n_iter=100) model.fit(train_vectors, train_targets) SGDClassifier(alpha=0.0001, average=False, class_weight=None, epsilon=0.1, eta0=0.0, fit_intercept=True, l1_ratio=0.15, learning_rate='optimal', loss='log', n_iter=100, n_jobs=1, penalty='l2', power_t=0.5, random_state=0, shuffle=True, verbose=0, warm_start=False) 

Nous évaluons le classificateur sur des vecteurs de test. Il montre une précision de 95%. Pas mal.

accuracy_score(model.predict(test_vectors), test_targets)
0.95022624434389136


Nous définissons la fonction de prédiction de tonalité pour certains mots, puis nous l'utilisons pour quelques exemples de données de test.

 def vecs_to_sentiment(vecs): # predict_log_proba  log-    predictions = model.predict_log_proba(vecs) #        #  log-    . return predictions[:, 1] - predictions[:, 0] def words_to_sentiment(words): vecs = embeddings.loc[words].dropna() log_odds = vecs_to_sentiment(vecs) return pd.DataFrame({'sentiment': log_odds}, index=vecs.index) #  20      words_to_sentiment(test_labels).ix[:20] 

tonalité
agiter-9,931679
interrompre-9,634706
fermement1.466919
imaginaire-2.989215
fiscalité0,468522
mondialement connu6.908561
bon marché9.237223
déception-8,737182
totalitaire-10,851580
belligérant-8.328674
se fige-8,456981
péché-7,839670
fragile-4.018289
dupe-4.309344
non résolu-2.816172
habilement2,333609
diabolise-2.102152
insouciant8.747150
impopulaire-7,887475
sympathiser1.790899

On voit que le classificateur fonctionne. Il a appris à généraliser la tonalité des mots en dehors des données d'entraînement.

Étape 4. Obtenez un score de tonalité pour le texte.


Il existe de nombreuses façons d'ajouter des vecteurs à une estimation globale. Encore une fois, nous suivons le chemin de la moindre résistance, il suffit donc de prendre la valeur moyenne.

 import re TOKEN_RE = re.compile(r"\w.*?\b") # regex  ,     (\w)   #   (.+?)    (\b).   #       . def text_to_sentiment(text): tokens = [token.casefold() for token in TOKEN_RE.findall(text)] sentiments = words_to_sentiment(tokens) return sentiments['sentiment'].mean() 

Il y a beaucoup à demander pour l'optimisation:

  • Introduire une relation inverse entre le poids du mot et sa fréquence, de sorte que les mêmes prépositions n'affectent pas beaucoup la tonalité.
  • Réglage pour que les phrases courtes ne se terminent pas par des valeurs de tonalité extrêmes.
  • Phrases comptables.
  • Un algorithme de segmentation de mots plus fiable que les apostrophes ne renversent pas.
  • Comptabilisation des négatifs comme «non satisfait».

Mais tout nécessite un code supplémentaire et ne changera pas fondamentalement les résultats. Au moins maintenant, vous pouvez comparer grossièrement différentes offres:

 text_to_sentiment("this example is pretty cool") 3.889968926086298 

 text_to_sentiment("this example is okay") 2.7997773492425186 

 text_to_sentiment("meh, this example sucks") -1.1774475917460698 

Étape 5. Voici le monstre que nous avons créé


Toutes les phrases n'ont pas une tonalité prononcée. Voyons ce qui se passe avec les phrases neutres:

 text_to_sentiment("Let's go get Italian food") 2.0429166109408983 

 text_to_sentiment("Let's go get Chinese food") 1.4094033658140972 

 text_to_sentiment("Let's go get Mexican food") 0.38801985560121732 

J'ai déjà rencontré un tel phénomène lors de l'analyse des avis de restaurants en tenant compte des représentations vectorielles des mots. Sans raison apparente , tous les restaurants mexicains ont un score global inférieur .

Les représentations vectorielles capturent de subtiles différences sémantiques dans leur contexte. Par conséquent, ils reflètent les préjugés de notre société.

Voici quelques autres suggestions neutres:

 text_to_sentiment("My name is Emily") 2.2286179364745311 

 text_to_sentiment("My name is Heather") 1.3976291151079159 

 text_to_sentiment("My name is Yvette") 0.98463802132985556 

 text_to_sentiment("My name is Shaniqua") -0.47048131775890656 

Bon sang ...

Le système associé aux noms des gens des sentiments complètement différents. Vous pouvez consulter ces exemples et bien d'autres et voir que la tonalité est généralement plus élevée pour les noms stéréotypés blancs et inférieure pour les noms stéréotypés noirs.

Ce test a été utilisé par Caliscan, Bryson et Narayanan dans leur article de recherche publié dans la revue Science en avril 2017. Cela prouve que la sémantique du corpus linguistique contient les préjugés de la société . Nous utiliserons cette méthode.

Étape 6. Évaluation du problème


Nous voulons comprendre comment éviter de telles erreurs. Passons plus de données dans le classificateur et mesurons statistiquement son «biais».

Ici, nous avons quatre listes de noms qui reflètent des origines ethniques différentes, principalement aux États-Unis. Les deux premiers sont des listes de noms à prédominance «blanche» et «noire», adaptés sur la base d'un article de Kaliskan et al. J'ai également ajouté des noms espagnols et musulmans de l'arabe et de l'ourdou.

Ces données sont utilisées pour vérifier le biais de l'algorithme pendant le processus de construction de ConceptNet: elles peuvent être trouvées dans le module conceptnet5.vectors.evaluation.bias . L'idée est d'étendre le dictionnaire à d'autres groupes ethniques, en tenant compte non seulement des noms, mais aussi des noms de famille.

Voici les listes:

 NAMES_BY_ETHNICITY = { #           . 'White': [ 'Adam', 'Chip', 'Harry', 'Josh', 'Roger', 'Alan', 'Frank', 'Ian', 'Justin', 'Ryan', 'Andrew', 'Fred', 'Jack', 'Matthew', 'Stephen', 'Brad', 'Greg', 'Jed', 'Paul', 'Todd', 'Brandon', 'Hank', 'Jonathan', 'Peter', 'Wilbur', 'Amanda', 'Courtney', 'Heather', 'Melanie', 'Sara', 'Amber', 'Crystal', 'Katie', 'Meredith', 'Shannon', 'Betsy', 'Donna', 'Kristin', 'Nancy', 'Stephanie', 'Bobbie-Sue', 'Ellen', 'Lauren', 'Peggy', 'Sue-Ellen', 'Colleen', 'Emily', 'Megan', 'Rachel', 'Wendy' ], 'Black': [ 'Alonzo', 'Jamel', 'Lerone', 'Percell', 'Theo', 'Alphonse', 'Jerome', 'Leroy', 'Rasaan', 'Torrance', 'Darnell', 'Lamar', 'Lionel', 'Rashaun', 'Tyree', 'Deion', 'Lamont', 'Malik', 'Terrence', 'Tyrone', 'Everol', 'Lavon', 'Marcellus', 'Terryl', 'Wardell', 'Aiesha', 'Lashelle', 'Nichelle', 'Shereen', 'Temeka', 'Ebony', 'Latisha', 'Shaniqua', 'Tameisha', 'Teretha', 'Jasmine', 'Latonya', 'Shanise', 'Tanisha', 'Tia', 'Lakisha', 'Latoya', 'Sharise', 'Tashika', 'Yolanda', 'Lashandra', 'Malika', 'Shavonn', 'Tawanda', 'Yvette' ], #         . 'Hispanic': [ 'Juan', 'José', 'Miguel', 'Luís', 'Jorge', 'Santiago', 'Matías', 'Sebastián', 'Mateo', 'Nicolás', 'Alejandro', 'Samuel', 'Diego', 'Daniel', 'Tomás', 'Juana', 'Ana', 'Luisa', 'María', 'Elena', 'Sofía', 'Isabella', 'Valentina', 'Camila', 'Valeria', 'Ximena', 'Luciana', 'Mariana', 'Victoria', 'Martina' ], #       # ,   .     . # #          # -   .    #   ,    . # #       . 'Arab/Muslim': [ 'Mohammed', 'Omar', 'Ahmed', 'Ali', 'Youssef', 'Abdullah', 'Yasin', 'Hamza', 'Ayaan', 'Syed', 'Rishaan', 'Samar', 'Ahmad', 'Zikri', 'Rayyan', 'Mariam', 'Jana', 'Malak', 'Salma', 'Nour', 'Lian', 'Fatima', 'Ayesha', 'Zahra', 'Sana', 'Zara', 'Alya', 'Shaista', 'Zoya', 'Yasmin' ] } 

À l'aide de Pandas, nous compilerons un tableau des noms, de leur origine ethnique prédominante et de leur tonalité:

 def name_sentiment_table(): frames = [] for group, name_list in sorted(NAMES_BY_ETHNICITY.items()): lower_names = [name.lower() for name in name_list] sentiments = words_to_sentiment(lower_names) sentiments['group'] = group frames.append(sentiments) #           return pd.concat(frames) name_sentiments = name_sentiment_table() 

Exemples de données:

name_sentiments.ix[::25]
tonalitéle groupe
mohammed0,834974Arabe / Musulman
alya3.916803Arabe / Musulman
terryl-2.858010Noir
josé0,432956Hispanique
luciana1.086073Hispanique
écheveau0,391858Blanc
megan2.158679Blanc

Nous allons faire un graphique de la distribution de la tonalité pour chaque nom.

 plot = seaborn.swarmplot(x='group', y='sentiment', data=name_sentiments) plot.set_ylim([-10, 10]) 

(-10, 10)



Ou sous forme d'histogramme avec des intervalles de confiance pour la moyenne de 95%.

 plot = seaborn.barplot(x='group', y='sentiment', data=name_sentiments, capsize=.1) 



Enfin, exécutez le package de statistiques statsmodels sérieux. Il montrera à quel point le biais de l'algorithme est important (avec un tas d'autres statistiques).


Résultats de la régression OLS
Dep. Variable:sentimentR au carré:0,208
Modèle:OLSAdj. R au carré:0,192
Méthode:Les moindres carrésStatistique F:04/13
Date:Jeu, 13 juil 2017Prob (statistique F):1.31e-07
Heure:11:31:17Log-vraisemblance:-356,78
Non. Observations:153AIC:721,6
Résidus Df:149BIC:733,7
Modèle Df:3
Type de covariance:nonrobust

La statistique F est le rapport entre la variation entre les groupes et la variation au sein des groupes, qui peut être considérée comme une évaluation générale du biais.

Immédiatement en dessous, il est indiqué la probabilité que nous voyions la statistique F maximale avec l'hypothèse nulle: c'est-à-dire en l'absence de différence entre les options comparées. La probabilité est très, très faible. Dans un article scientifique, nous qualifierions le résultat de "très statistiquement significatif".

Nous devons améliorer la valeur F. Le plus bas sera le mieux.

ols_model.fvalue
13.041597745167659


Étape 7. Essayer d'autres données.


Nous avons maintenant la possibilité de mesurer numériquement le biais nocif du modèle. Essayons de l'ajuster. Pour ce faire, vous devez répéter un tas de choses qui n'étaient que des étapes distinctes dans un bloc-notes Python.

Si j'écrivais du bon code, je n'utiliserais pas de variables globales telles que le model et les embeddings . Mais le code spaghetti actuel vous permet de mieux examiner chaque étape et de comprendre ce qui se passe. Nous réutilisons une partie du code et définissons au moins une fonction pour répéter certaines étapes:

 def retrain_model(new_embs): """      . """ global model, embeddings, name_sentiments embeddings = new_embs pos_vectors = embeddings.loc[pos_words].dropna() neg_vectors = embeddings.loc[neg_words].dropna() vectors = pd.concat([pos_vectors, neg_vectors]) targets = np.array([1 for entry in pos_vectors.index] + [-1 for entry in neg_vectors.index]) labels = list(pos_vectors.index) + list(neg_vectors.index) train_vectors, test_vectors, train_targets, test_targets, train_labels, test_labels = \ train_test_split(vectors, targets, labels, test_size=0.1, random_state=0) model = SGDClassifier(loss='log', random_state=0, n_iter=100) model.fit(train_vectors, train_targets) accuracy = accuracy_score(model.predict(test_vectors), test_targets) print("Accuracy of sentiment: {:.2%}".format(accuracy)) name_sentiments = name_sentiment_table() ols_model = statsmodels.formula.api.ols('sentiment ~ group', data=name_sentiments).fit() print("F-value of bias: {:.3f}".format(ols_model.fvalue)) print("Probability given null hypothesis: {:.3}".format(ols_model.f_pvalue)) #        Y plot = seaborn.swarmplot(x='group', y='sentiment', data=name_sentiments) plot.set_ylim([-10, 10]) 

Nous essayons word2vec


On peut supposer que seul GloVe a le problème. Il y a probablement beaucoup de sites douteux dans la base de données Common Crawl et au moins 20 copies du dictionnaire urbain d'argot de rue. Peut-être que sur une base différente, ce sera mieux: qu'en est-il du bon vieux word2vec formé sur Google News?

Il semble que la source la plus fiable pour les données word2vec soit ce fichier sur Google Drive . Téléchargez-le et enregistrez-le sous data/word2vec-googlenews-300.bin.gz .

 #   ConceptNet   word2vec   Pandas     from conceptnet5.vectors.formats import load_word2vec_bin w2v = load_word2vec_bin('data/word2vec-googlenews-300.bin.gz', nrows=2000000) #  word2vec    w2v.index = [label.casefold() for label in w2v.index] #  ,    w2v = w2v.reset_index().drop_duplicates(subset='index', keep='first').set_index('index') retrain_model(w2v) 

Accuracy of sentiment: 94.30%
F-value of bias: 15.573
Probability given null hypothesis: 7.43e-09


Word2vec s'est donc avéré encore pire avec une valeur F supérieure à 15.

En principe, il était insensé de s'attendre à ce que les informations soient mieux protégées contre les biais.

Essayer ConceptNet Numberbatch


Enfin, je peux parler de mon propre projet sur la représentation vectorielle des mots.

ConceptNet avec la fonction de présentation vectorielle est le graphe de connaissances sur lequel je travaille. Il normalise les représentations vectorielles au stade de la formation, identifiant et supprimant certaines sources de racisme et de sexisme algorithmiques. Cette méthode de correction du biais est basée sur un article scientifique de Bulukbashi et al. «Debiasing Word Embeddings» et est généralisée pour éliminer plusieurs types de biais en même temps. À ma connaissance, c'est le seul système sémantique dans lequel il y a quelque chose comme ça.

De temps en temps, nous exportons des vecteurs précalculés depuis ConceptNet - ces versions sont appelées ConceptNet Numberbatch . En avril 2017, la première version avec correction du biais a été publiée, nous allons donc charger les vecteurs de langue anglaise et recycler notre modèle.

numberbatch-en-17.04b.txt.gz , l'enregistrons dans le répertoire data/ et recyclons le modèle:

 retrain_model(load_embeddings('data/numberbatch-en-17.04b.txt')) 

Accuracy of sentiment: 97.46%
F-value of bias: 3.805
Probability given null hypothesis: 0.0118




Alors, ConceptNet Numberbatch a-t-il complètement résolu le problème? Plus de racisme algorithmique? Non.

Le racisme est-il devenu beaucoup moins? Certainement .

Les plages de clés pour les groupes ethniques se chevauchent beaucoup plus que dans les vecteurs GloVe ou word2vec. Par rapport à GloVe, la valeur de F a diminué de plus de trois fois, et par rapport à word2vec - de plus de quatre fois. Et en général, nous voyons des différences de tonalité beaucoup plus petites lors de la comparaison de différents noms: cela devrait être le cas, car les noms ne devraient vraiment pas affecter le résultat de l'analyse.

Mais une légère corrélation subsiste. Je peux peut-être récupérer des données et des paramètres d'entraînement tels que le problème semble être résolu. Mais ce sera une mauvaise option, car en fait le problème demeure, car dans ConceptNet nous n'avons pas identifié et compensé toutes les causes du racisme algorithmique. Mais c'est un bon début.

Pas d'embûches


Veuillez noter qu'avec le passage à ConceptNet Numberbatch, la précision de la prédiction de la tonalité s'est améliorée.

Quelqu'un aurait pu suggérer que la correction du racisme algorithmique aggraverait les résultats d'une autre manière. Mais non. Vous pouvez avoir des données meilleures et moins racistes. . word2vec GloVe .


, . - .

. , .

, . , — . , . (recall), — .

, - . . , , . , .

Source: https://habr.com/ru/post/fr436506/


All Articles