Løken, eller ikke løken?

The Onion (advarsel: mange artikler er NSFW) er en satirisk nyhetsorganisasjon som parodierer tradisjonelle nyhetsmedier. I 2014 lanserte The Onion ClickHole (advarsel: også ofte NSFW), et satirisk nyhetsnettsted som parodierer «clickbait» -sider som BuzzFeed. Takket være Poes Law , er det ganske vanlig at folk leser overskriftene på artikler fra The Onion eller ClickHole og tror at de er sanne, uten å vite at de er ment å være satire. Det omvendte skjer også med latterlig virkelige nyhetshistorier – folk tror ofte at de er satire når de ikke er det.

Denne forvirringen gir seg naturlig til et spill – gitt en nyhetsoverskrift, prøv å gjette om eller ikke det er satire. Denne utfordringen handler om å gjøre akkurat det med et program.

Gitt en nyhetsoverskrift (en streng som bare består av utskrivbare ASCII-tegn og mellomrom), skriv ut 1 hvis overskrift er satire, eller 0 hvis den ikke er det. Poengsummen din vil være antall riktige utganger delt på totalt antall overskrifter.

Som vanlig, standard smutthull (spesielt optimalisering for testsakene ) er ikke tillatt. For å håndheve dette vil jeg kjøre programmene dine på et sett med 200 skjulte testtilfeller (100 fra The Onion, 100 fra Not The Onion). Løsningen din må ikke score mer enn 20 prosentpoeng mindre enn poengsummen din i de offentlige testsakene for å være gyldig.

Testsaker

Å komme med testsaker for denne utfordringen , Jeg valgte 25 overskrifter fra The Onion subreddit (der artikler fra The Onion og dets underordnede nettsteder, som ClickHole, blir lagt ut), og 25 overskrifter fra Not The Onion subreddit (der det legges ut virkelige nyhetsartikler som høres ut som satire). De eneste endringene jeg gjorde i overskriftene, var å erstatte «fancy» sitater med vanlige ASCII-anførselstegn og standardisere store bokstaver – alt annet blir uendret fra den opprinnelige artikkelens overskrift. Hver overskrift er på sin egen linje.

Løkoverskriftene

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 

Ikke løkoverskriftene

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 

Kommentarer

  • Your score will be the number of correct outputs divided by the total number of headlines Er byteller en uavgjort?
  • Jeg ‘ en liten bit forvirret. Hvilken type løsning forventer du? Hver løsning må » optimalisere for testtilfellene » noe, bar skriver en AI som kan forstå engelsk og har sans for humor. For eksempel oppdager Arnauld ‘ løsning /ly\b/ som bare fungerer fordi 25 Onio Overskrifter du valgte har tilfeldigvis flere adverb, men for alt vet jeg at du enkelt kan kaste den opp med et annet testbatteri. Og hvem ‘ skal si at koeffisientene ikke ‘ ikke valgte å optimalisere poengsummen? (Hvorfor ville ‘ ikke optimalisere dem?)
  • Dette testbatteriet virker litt uvanlig. Det ‘ er som å be om en klassifikator som kan oppdage hunder på et fotografi, men å ta positive testtilfeller som bilder av hunder og negative testtilfeller fra en Buzzfeed-artikkel med tittelen » 25 bilder av gjenstander du ‘ ll Swear Are Dogs, But Nope, Turns Out They Aren ‘ t! (# 11 Will Blow Your Mind!) » Det gjør et vanskelig nok problem vanskeligere.
  • Ikke bare er utfordringen vanskelig, men den ‘ er også ikke opplagt (for meg) hva ‘ er forskjellen. Hvis jeg ikke kan ‘ ikke løse det, kan selvfølgelig programmet mitt ‘ t løse det (det vil si mens jeg overbeviser meg om at det ikke ‘ t hardcode for testsakene)
  • Vel, jeg brukte +36 timer på å trene et kunstig nevralt nettverk ved hjelp av brain.js og LSTM, med eksempler i dette nummeret og 100 andre eksempler av hver type fra gitt lenker, men resultatet var ikke ‘ t godt nok med nye titler som ikke var ‘ ikke til stede i treningssett. Jeg ‘ er ferdig: P

Svar

JavaScript ( ES7), 39/50 (78%)

63,5% (127/200) om skjulte testtilfeller

En enkel heuristikk basert på tittelens lengde, antall mellomrom og bruk av -ly suffikset.

 isOnion = str => str.length ** 0.25 + str.split(" ").length ** 1.25 * 2 + str.split(/ly\b/).length ** 1.75 * 7 > 76  

Prøv det online!

Kommentarer

  • Dette er absurd effektivt for hvor enkelt det er.
  • Denne løsningen fikk 63,5% på de skjulte testtilfellene, så det er gyldig.
  • Ikke så enkelt som det var mulig i begynnelsen av sandkassen (100%, ved å bruke store bokstaver før den ble standardisert), men dette er veldig enkelt.
  • @ Mego Bare av nysgjerrighet, forbedrer denne NSFW-versjonen poengsummen på de skjulte testsakene? 🙂
  • @Arnauld 66% med den versjonen

Svar

Python 3, 84%

Utestet på skjulte testtilfeller.

Dette bruker Keras LSTM RNN trent på forskjellige overskrifter. For å kjøre det trenger du Keras følgende og modellen som jeg har gjort tilgjengelig på GitHub: repo link . Du trenger modellen .h5 og ord- / vektorkartleggingen er i .pkl. De siste

Avhengighetene er:

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 

Innstillingene er:

max_headline_length = 70 word_count = 20740 

Modellen er:

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")) 

Nå for å laste inn modellen og ordet embeddings:

model.load_weights("model.h5") word_to_index = load(open("words.pkl", "rb")) 

Og koden for å teste om en streng er fra «NotTheOnion» eller «TheOnion «Jeg har skrevet en rask hjelperfunksjon som konverterer strengen til de respektive ordinnblandingene:

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 

Forklaring

Denne koden kjører en modell som analyserer forholdet mellom ord ved å representere ordene som en «vektor». Du kan lære mer om innebygging av ord her .

Dette blir trent på overskrifter, men testtilfellene er ekskludert .

Disse prosessene blir automatisert etter ganske mye behandling. Jeg har distribuert den endelige behandlede ordlisten som en .pkl men det som skjer i ordinnbetting er først vi analyserer setningen og isolerer ordene.

Etter at vi nå har ordene neste trinn er å kunne forstå forskjellene og likhetene mellom bestemte ord f.eks. king og queen versus duke og duchess. Disse embeddingene skjer ikke mellom ordene, men mellom tall som representerer ordene, det er det som er lagret i .pkl fil. Ord som maskinen ikke forstår er kartlagt til et spesielt ord <UNK> som lar oss forstå at det er et ord der, men at det ikke er kjent nøyaktig hva meningen er.

Nå som ordene kan forstås, må ordrekkefølgen (overskrift) kunne analyseres. Dette er hva «LSTM» gjør, en LTSM er en type «RNN» -celle som unngår den forsvinnende gradienteffekten. Enklere tar det i en ordsekvens, og det lar oss finne forhold mellom dem.

Nå er det siste laget Dense som i utgangspunktet betyr at den er som en matrise som betyr at utgangen er som: [probability_is_not_onion, probability_is_onion]. Ved å finne hvilken som er større kan vi velge hvilken som er det mest sikre resultatet for den gitte overskriften.

Svar

Python 3 + Keras, 41/50 = 82%

83% (166/200) på skjulte testsaker

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 og vocabulary.json kan hentes fra her (veldig stor) og her .

Fullt tilkoblet klassifikator koblet til en forhåndstrent sentimentanalysemodell DeepMoji, som består av stablede toveis LSTM og en oppmerksomhetsmekanisme. Jeg frøs DeepMoji-lagene og tok ut det endelige softmax-laget, trente bare de fullt sammenkoblede lagene, så løsnet DeepMoji-lagene og trente dem sammen for finjustering. Oppmerksomhetsmekanismen er hentet fra https://github.com/bfelbo/DeepMoji/blob/master/deepmoji/attlayer.py (Jeg ønsket ikke å måtte bruke all koden sin som en avhengighet for en klasse, spesielt siden den er Python 2 og ganske uhåndterlig å bruke som en modul …)

Dette fungerer overraskende dårlig på Megos testsett, med tanke på at det på min egen større validering satt det får> 90%. Så jeg er ikke ferdig med dette ennå.

Kommentarer

  • 83% på skjulte testsaker, forutsatt at jeg kjørte det riktig

Svar

JavaScript ( Node.js ), 98% (49/50)

96% (192/200) på skjulte testsaker

 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)); };  

Dette krever to store JSON-filer som jeg ikke kan sette dem her eller på » TiO «. Last ned dem fra følgende lenker og lagre dem med words.json og navn, i samme mappe som JS-fil. Det er også en lenke for en JS-fil med testtilfeller og utskrift / resultat / prosent.Du kan plassere skjulte testtilfeller i onions og nonOnions variabler.

Etter å ha lagret alle 3 filene i samme katalog, kjør node onion.js.

O -funksjonen returnerer true hvis det er løk og false hvis det ikke er «t. Bruker en stor liste med ordposer (uten ordre) for å oppdage om inngangsstrengen er løk. Litt hardkodet, men fungerer veldig bra på en rekke tilfeldige tester saker.

Kommentarer

  • Denne løsningen får 96% på de skjulte testtilfellene

Svar

Arbeider av Arnaulds løsning

JavaScript (ES6), 41/50

64% (128/200) på skjult testtilfeller

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) på skjulte testtilfeller (ugyldig)

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 

Lengden + ordtall + «ly «konseptet fungerer ganske bra, jeg klarte å klemme ut noen flere poeng ved å se etter ordet» pappa «(når snakker ekte artikler om folks pappaer i tredje person i tittelen?) og et ekstra poeng ved å endre «ly» -søket heuristisk og sjekk for tilstedeværelsen av tall i tittelen (som kan være mindre gyldig i det generelle tilfellet utenfor testen, så jeg la igjen begge løsningene)

Kommentarer

  • Jeg vet ikke ‘ jeg vet ikke om pappadelen … virker litt som å optimalisere testsaken for meg …
  • Og ja, jeg finner mange Not The Onion-artikler som nevner pappaer
  • Det ‘ er sannsynligvis en bedre måte å gjøre det som en del av heuristikken og ikke bare en hard » vinn » hvis den inneholder pappa, men jeg forestiller meg at jeg selv utenfor testdatabasen abstrakt snakker om en spesifikk » Pappa » er mer vanlig på The Onion
  • Din første løsning fikk 64% på skjulte testtilfeller, så den er gyldig. Den andre løsningen din fikk 62,5% på skjulte testtilfeller, så den er ikke gyldig.
  • @Mego Hva en nær margin …

Legg igjen en kommentar

Din e-postadresse vil ikke bli publisert. Obligatoriske felt er merket med *