Ceapa (avertisment: multe articole sunt NSFW) este o organizație de știri satirică care parodieză știrile tradiționale. În 2014, The Onion a lansat ClickHole (avertisment: de asemenea frecvent NSFW), un site de știri satirice care parodizează site-uri „clickbait” precum BuzzFeed. Datorită legii Poe , este destul de obișnuit ca oamenii să citească titlurile articolelor din The Onion sau ClickHole și să le creadă adevărate, fără să știe că sunt destinate să fie satiră. Conversa se întâmplă și cu știrile reale cu sunete ridicole – oamenii cred adesea că sunt satire atunci când nu sunt.
Această confuzie se pretează în mod natural unui joc – având în vedere titlul unei știri, încercați să ghiciți dacă sau nu este satiră. Această provocare este aceea de a face exact asta cu un program.
Având în vedere un titlu de știre (un șir format doar din caractere și spații ASCII tipărite), ieșire 1
dacă titlul este satiră sau 0
dacă nu este. Scorul dvs. va fi numărul de rezultate corecte împărțit la numărul total de titluri.
Ca de obicei, lacune standard (în special optimizarea pentru cazurile de testare ) nu sunt permise. Pentru a pune în aplicare acest lucru, voi rula programele dvs. pe un set de 200 de cazuri de test ascunse (100 din The Onion, 100 din Not The Onion). Soluția dvs. trebuie să înregistreze cu cel puțin 20 de puncte procentuale mai puțin decât scorul dvs. la cazurile de testare publice pentru a fi valabilă.
Cazuri de testare
Pentru a veni cu cazuri de testare pentru această provocare , Am ales 25 de titluri din Subreddit-ul Onion (unde sunt postate articole din The Onion și site-urile copilului său, precum ClickHole) și 25 de titluri din subreditul Not The Onion (unde sunt postate articole de știri reale care sună ca satiră). Singurele modificări pe care le-am făcut titlurilor au fost înlocuirea ghilimelelor „fanteziste” cu ghilimele ASCII obișnuite și standardizarea majusculelor – orice altceva rămâne neschimbat față de titlul articolului original. Fiecare titlu este pe linia sa. Titlurile Onion
Trump Warns Removing Confederate Statues Could Be Slippery Slope To Eliminating Racism Entirely "No Way To Prevent This," Says Only Nation Where This Regularly Happens My Doctor Told Me I Should Vaccinate My Children, But Then Someone Much Louder Than My Doctor Told Me I Shouldn"t Man At Park Who Set Up Table Full Of Water Cups Has No Idea How Passing Marathon Runners Got Impression They Can Take Them This Child Would Have Turned 6 Today If His Mother Hadn"t Given Birth To Him In October Incredible Realism: The Campaign In The Next "Call Of Duty" Will Begin At Your Avatar"s High School Cafeteria When He"s Being Tricked Into Joining The Military By A Recruiter "Sometimes Things Have To Get Worse Before They Get Better," Says Man Who Accidentally Turned Shower Knob Wrong Way Report: Uttering Phrase "Easy Does It" Prevents 78% Of Drywall Damage While Moving Furniture Barbara Bush Passes Away Surrounded By Loved Ones, Jeb Family Has Way Too Many Daughters For Them Not To Have Been Trying For Son News: Privacy Win! Facebook Is Adding A "Protect My Data" Button That Does Nothing But Feels Good To Press Dalai Lama Announces Next Life To Be His Last Before Retirement Researchers Find Decline In Facebook Use Could Be Directly Linked To Desire To Be Happy, Fully Functioning Person Manager Of Combination Taco Bell/KFC Secretly Considers It Mostly A Taco Bell Trump: "It"s My Honor To Deliver The First-Ever State Of The Union" Daring To Dream: Jeff Bezos Is Standing Outside A Guitar Center Gazing Longingly At A $200 Billion Guitar Area Dad Looking To Get Average Phone Call With Adult Son Down To 47.5 Seconds Experts Warn Beef Could Act As Gateway Meat To Human Flesh Jeff Bezos Named Amazon Employee Of The Month Dad Suggests Arriving At Airport 14 Hours Early Report: Only 3% Of Conversations Actually Need To Happen Delta Pilot Refuses To Land Until Gun Control Legislation Passed Family Wishes Dad Could Find Healthier Way To Express Emotions Than Bursting Into Full-Blown Musical Number New Honda Commercial Openly Says Your Kids Will Die In A Car Crash If You Buy A Different Brand Teacher Frustrated No One In Beginner Yoga Class Can Focus Chakras Into Energy Blast
Nu The Onion titlurile
Man Rescued From Taliban Didn"t Believe Donald Trump Was President Nat Geo Hires Jeff Goldblum To Walk Around, Being Professionally Fascinated By Things Mike Pence Once Ratted Out His Fraternity Brothers For Having A Keg Reddit CEO Tells User, "We Are Not The Thought Police," Then Suspends That User Trump Dedicates Golf Trophy To Hurricane Victims Uber"s Search For A Female CEO Has Been Narrowed Down To 3 Men ICE Director: ICE Can"t Be Compared To Nazis Since We"re Just Following Orders Passenger Turned Away From Two Flights After Wearing 10 Layers Of Clothing To Avoid Luggage Fee Somali Militant Group Al-Shabaab Announces Ban On Single-Use Plastic Bags UPS Loses Family"s $846k Inheritance, Offers To Refund $32 Shipping Fee Teen Suspended From High School After Her Anti-Bullying Video Hurts Principal"s Feelings Alabama Lawmaker: We Shouldn"t Arm Teachers Because Most Are Women Cat Named After Notorious B.I.G. Shot Multiple Times - And Survives EPA Head Says He Needs To Fly First Class Because People Are Mean To Him In Coach Apology After Japanese Train Departs 20 Seconds Early Justin Bieber Banned From China In Order To "Purify" Nation Alcohol Level In Air At Fraternity Party Registers On Breathalyzer NPR Tweets The Declaration Of Independence, And People Freak Out About A "Revolution" Man Who Mowed Lawn With Tornado Behind Him Says He "Was Keeping An Eye On It." After Eating Chipotle For 500 Days, An Ohio Man Says He"s Ready For Something New "El Chapo" Promises Not To Kill Any Jurors From Upcoming Federal Trial After 4th DWI, Man Argues Legal Limit Discriminates Against Alcoholics Palestinian Judge Bans Divorce During Ramadan Because "People Make Hasty Decisions When They"re Hungry" Argentinian Officers Fired After Claiming Mice Ate Half A Ton Of Missing Marijuana "Nobody Kill Anybody": Murder-Free Weekend Urged In Baltimore
Comentarii
Răspuns
JavaScript ( ES7), 39/50 (78%)
63,5% (127/200) pentru cazuri de test ascunse
O euristică simplă bazată pe lungimea titlului, numărul de spații și utilizarea sufixului -ly
.
isOnion = str => str.length ** 0.25 + str.split(" ").length ** 1.25 * 2 + str.split(/ly\b/).length ** 1.75 * 7 > 76
Comentarii
- Acest lucru este absurd de eficient pentru cât de simplă este.
- Această soluție a obținut 63,5% pe cazurile de test ascunse, deci este valabil.
- Nu este atât de simplu cât era posibil la începutul sandbox-ului (100%, folosind diferențe de majuscule înainte de a fi standardizat), dar acest lucru este foarte simplu.
- @Mego Doar din curiozitate, această versiunea NSFW îmbunătățește scorul pentru cazurile de test ascunse? 🙂
- @Arnauld 66% cu acea versiune
Răspuns
Python 3, 84%
Netestat pe cazuri de test ascunse.
Aceasta folosește Keras LSTM RNN instruit pe diferite titluri. Pentru a-l rula, aveți nevoie de Keras de următoarele și de modelul pe care l-am „pus la dispoziție pe GitHub: link repo . Veți avea nevoie de modelul .h5
și mapările de cuvinte / vectori sunt în .pkl
. Cel mai recent
Dependențele sunt:
import numpy as np from pickle import load from keras.preprocessing import sequence, text from keras.models import Sequential from keras.layers import Dense, Embedding, SpatialDropout1D, LSTM, Dropout from keras.regularizers import l2 import re
Setările sunt:
max_headline_length = 70 word_count = 20740
Modelul este:
model = Sequential() model.add(Embedding(word_count, 32, input_length=max_headline_length)) model.add(SpatialDropout1D(0.4)) model.add(LSTM(64, kernel_regularizer=l2(0.005), dropout=0.3, recurrent_dropout=0.3)) model.add(Dropout(0.5)) model.add(Dense(32, kernel_regularizer=l2(0.005))) model.add(Dropout(0.5)) model.add(Dense(2, kernel_regularizer=l2(0.001), activation="softmax"))
Acum pentru a încărca modelul și încorporarea cuvântului:
model.load_weights("model.h5") word_to_index = load(open("words.pkl", "rb"))
Și codul pentru a testa dacă un șir provine de la „NotTheOnion” sau „TheOnion „Am” scris o funcție de asistență rapidă care convertește șirul la încorporările cuvintelor respective:
def get_words(string): words = [] for word in re.finditer("[a-z]+|[\"".;/!?]", string.lower()): words.append(word.group(0)) return words def words_to_indexes(words): return [word_to_index.get(word, 0) for word in words] def format_input(word_indexes): return sequence.pad_sequences([word_indexes], maxlen=max_headline_length)[0] def get_type(string): words = words_to_indexes(get_words(string)) result = model.predict(np.array([format_input(words)]))[0] if result[0] > result[1]: site = "NotTheOnion" else: site = "TheOnion" return site
Explicație
Acest cod rulează un model care analizează relațiile dintre cuvinte prin reprezentarea cuvintelor ca „vector”. Puteți afla mai multe despre încorporarea cuvintelor aici .
Acest lucru este instruit pe titluri, dar cazurile de testare sunt excluse .
Acest proces este automat după o prelucrare destul de mică. Am „distribuit lista finală de cuvinte procesate ca .pkl
, dar ceea ce se întâmplă în încorporarea cuvintelor este mai întâi să analizăm propoziția și să izolăm cuvintele.
După ce acum aveți cuvintele următorul pas este să puteți înțelege diferențele și asemănările dintre anumite cuvinte, de ex. king
și queen
versus duke
și duchess
. Aceste încorporări nu se întâmplă între cuvintele reale, ci între numerele care reprezintă cuvintele, care este ceea ce este stocat în .pkl
fișier. Cuvintele pe care aparatul nu le înțelege sunt mapate la un cuvânt special <UNK>
care ne permite să înțelegem că există un cuvânt acolo, dar că nu se știe exact care este semnificația.
Acum că cuvintele pot fi înțelese, succesiunea cuvintelor (titlul) trebuie să poată fi analizată. Aceasta este ceea ce face „LSTM”, un LTSM este un tip de celulă „RNN” care evită efectul gradientului de dispariție. Mai simplu, ia o secvență de cuvinte și ne permite să găsim relații între ele.
Acum stratul final este Dense
ceea ce înseamnă practic că este un fel de matrice, ceea ce înseamnă că ieșirea este ca: [probability_is_not_onion, probability_is_onion]
. Găsind care dintre acestea este mai mare putem alege care este rezultatul cel mai încrezător pentru titlul dat.
Răspuns
Python 3 + Keras, 41/50 = 82%
83% (166/200) pentru cazuri de test ascunse
import json import keras import numpy import re from keras import backend as K STRIP_PUNCTUATION = re.compile(r"[^a-z0-9 ]+") class AttentionWeightedAverage(keras.engine.Layer): def __init__(self, return_attention=False, **kwargs): self.init = keras.initializers.get("uniform") self.supports_masking = True self.return_attention = return_attention super(AttentionWeightedAverage, self).__init__(**kwargs) def build(self, input_shape): self.input_spec = [keras.engine.InputSpec(ndim=3)] assert len(input_shape) == 3 self.W = self.add_weight(shape=(input_shape[2], 1), name="{}_W".format(self.name), initializer=self.init) self.trainable_weights = [self.W] super(AttentionWeightedAverage, self).build(input_shape) def call(self, x, mask=None): logits = K.dot(x, self.W) x_shape = K.shape(x) logits = K.reshape(logits, (x_shape[0], x_shape[1])) ai = K.exp(logits - K.max(logits, axis=-1, keepdims=True)) if mask is not None: mask = K.cast(mask, K.floatx()) ai = ai * mask att_weights = ai / (K.sum(ai, axis=1, keepdims=True) + K.epsilon()) weighted_input = x * K.expand_dims(att_weights) result = K.sum(weighted_input, axis=1) if self.return_attention: return [result, att_weights] return result def get_output_shape_for(self, input_shape): return self.compute_output_shape(input_shape) def compute_output_shape(self, input_shape): output_len = input_shape[2] if self.return_attention: return [(input_shape[0], output_len), (input_shape[0], input_shape[1])] return (input_shape[0], output_len) def compute_mask(self, input, input_mask=None): if isinstance(input_mask, list): return [None] * len(input_mask) else: return None if __name__ == "__main__": model = keras.models.load_model("combined.h5", custom_objects={"AttentionWeightedAverage": AttentionWeightedAverage}) with open("vocabulary.json", "r") as fh: vocab = json.load(fh) while True: try: headline = input() except EOFError: break tokens = STRIP_PUNCTUATION.sub("", headline.lower()).split() inp = numpy.zeros((1, 45)) for i, token in enumerate(tokens): try: inp[0,i] = vocab[token] except KeyError: inp[0,i] = 1 print(model.predict(inp)[0][0] > 0.3)
combined.h5
și vocabulary.json
pot fi preluate de la aici (foarte mare) și aici .
Clasificator complet conectat conectat la un model de analiză a sentimentului pre-instruit DeepMoji, care constă din LSTM-uri bidirecționale stivuite și un mecanism atențional. Am înghețat straturile DeepMoji și am scos ultimul strat softmax, am antrenat doar straturile complet conectate, apoi am dezghețat straturile DeepMoji și le-am antrenat împreună pentru reglaj fin. Mecanismul atențional este preluat de la https://github.com/bfelbo/DeepMoji/blob/master/deepmoji/attlayer.py (nu doream să folosesc tot codul lor ca dependență pentru o clasă, mai ales că este Python 2 și este destul de dificil de utilizat ca modul …)
Acest lucru are o performanță surprinzător de slabă pe setul de testare al lui Mego, având în vedere că, pe propria mea validare mai mare, îl setează primește> 90%. Deci, încă nu am terminat cu acest lucru.
Comentarii
- 83% pentru cazurile de test ascunse, presupunând că l-am rulat corect
Răspuns
JavaScript ( Node.js ), 98% (49/50)
96% (192/200) pe cazuri de test ascunse
const words = require("./words"); const bags = require("./bags"); let W = s => s.replace(/[^A-Za-z0-9 ]/g, "").toLowerCase().split(" ").filter(w => w.length > 3); let M = b => { for (let i = 0; i < bags.length; i++) { let f = true; for (let j = 0; j < bags[i].length; j++) if (!b.includes(bags[i][j])) { f = false; break; } if (f) return true; } return false; }; let O = s => { let b = []; W(s).forEach(w => { let p = words.indexOf(w); if (p >= 0) b.push(p); }); return (b.length > 0 && M(b)); };
Acest lucru necesită două fișiere JSON mari pe care nu le pot pune aici sau pe ” TiO „. Vă rugăm să le descărcați din următoarele linkuri și să le salvați cu words.json
și nume, în același folder cu fișierul JS. Există, de asemenea, un link pentru un fișier JS cu cazuri de testare și imprimare rezultat / procent.Puteți pune cazurile de test ascunse în variabile onions
și nonOnions
.
- words.json
- bags.json
- onion.js (include cazurile de test implicite)
După salvarea tuturor celor 3 fișiere în același director, rulați node onion.js
.
Funcția O
va returna true
dacă este ceapă și false
dacă nu este. Folosește o listă mare de pungi de cuvinte (fără ordine) pentru a detecta dacă șirul de intrare este ceapă. Un fel de cod tare, dar funcționează foarte bine la o varietate de test aleatoriu cazuri.
Comentarii
- Această soluție obține 96% din cazurile de test ascunse
Răspuns
Lucrul cu soluția Arnauld
JavaScript (ES6), 41/50
64% (128/200) pe ascuns cazuri de testare
str.includes("Dad") || str.length ** .25 + str.split(" ").length ** 1.25 * 2 + str.split(/ly\b/).length ** 1.75 * 7 > 76
JavaScript (ES6), 42/50
62,5% (125/200) pentru cazurile de test ascunse (nevalid)
isOnion = str => str.includes("Dad") || str.length ** .25 + str.split(" ").length ** 1.25 * 2 + str.split(" ").filter(w => w.length > 3 && w.split(/ly/).length > 1).length * 23.54 + /\d/.test(str) * 8 > 76
Lungimea + numărul de cuvinte + „ly „Conceptul funcționează destul de bine, am reușit să mai scot câteva puncte verificând cuvântul„ tată ”(când vorbesc articole reale despre tăticii oamenilor la a treia persoană din titlu?) și un punct suplimentar prin schimbarea căutarea „ly” euristică și verificarea prezenței numerelor în titlu (ceea ce ar putea fi mai puțin valabil în cazul general în afara testului, așa că am lăsat ambele soluții)
Comentarii
- Nu ‘ nu știu despre partea tatălui … mi se pare cam optimizarea cazului de testare …
- Și da, pot găsi o mulțime de articole „Not the Onion” care menționează tati
- Există ‘ probabil o modalitate mai bună de a o face ca parte a euristicii și nu doar un ” câștigă ” dacă conține tată, dar îmi imaginez chiar și în afara bazei de date de testare vorbind abstract despre un anumit ” Tata ” este mai frecvent pe Theion
- Prima dvs. soluție a obținut 64% în cazurile de test ascunse, deci este validă. A doua soluție a obținut 62,5% în cazurile de test ascunse, deci nu este validă.
- @Mego Ce marjă strânsă …
Your score will be the number of correct outputs divided by the total number of headlines
Bytecount este un break break?/ly\b/
care funcționează doar pentru că 25 Onio n titlurile pe care le-ați ales se întâmplă să aibă mai multe adverbe, dar știu că ați putea să-l împiedicați cu o baterie de testare diferită. Și cine ‘ ar spune coeficienții săi ‘ nu au ales să-și optimizeze scorul? (De ce ‘ nu le-ar optimiza?)brain.js
și LSTM, cu eșantioane în acest număr și alte 100 de eșantioane de fiecare tip din legăturile furnizate, dar rezultatul nu a fost ‘ t suficient de bun cu titluri noi care nu au fost ‘ t prezent în seturile de antrenament. Am ‘ terminat: P