Løg eller ikke løg?

The Onion (advarsel: mange artikler er NSFW) er en satirisk nyhedsorganisation, der parodierer traditionelle nyhedsmedier. I 2014 lancerede The Onion ClickHole (advarsel: også ofte NSFW), et satirisk nyhedswebsted, der parodierer “clickbait” -sider som BuzzFeed. Takket være Poes lov er det ret almindeligt, at folk læser overskrifterne på artikler fra The Onion eller ClickHole og mener, at de er sande uden at vide at de er beregnet til at være satire. Det omvendte sker også med latterligt klingende rigtige nyhedshistorier – folk tror ofte, at de er satire, når de ikke er det.

Denne forvirring egner sig naturligvis til et spil – givet en nyhedsoverskrift, prøv at gætte, om eller ikke det er satire. Denne udfordring handler om at gøre præcis det med et program.

I betragtning af en nyhedsoverskrift (en streng bestående af kun ASCII-tegn og mellemrum, der kan udskrives), skal du output 1 hvis overskrift er satire, eller 0, hvis den ikke er det. Din score vil være antallet af korrekte output divideret med det samlede antal overskrifter.

Som sædvanlig er standard smuthuller (især optimering til testsager ) er ikke tilladt. For at håndhæve dette vil jeg køre dine programmer på et sæt på 200 skjulte testsager (100 fra The Onion, 100 fra Not The Onion). Din løsning må ikke score mere end 20 procentpoint mindre end din score på de offentlige testsager for at være gyldig.

Testcases

At komme med testcases til denne udfordring , Jeg valgte 25 overskrifter fra The Onion subreddit (hvor artikler fra The Onion og dets underordnede websteder, som ClickHole, er udgivet) og 25 overskrifter fra underredditen Not The Onion (hvor rigtige nyhedsartikler, der lyder som satire, udgives). De eneste ændringer, jeg foretog i overskrifterne, var at erstatte “fancy” citater med regelmæssige ASCII-citater og standardisere store bogstaver – alt andet er uændret i forhold til den originale artikels overskrift. Hver overskrift er på sin egen linje.

Løgoverskrifterne

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 The Onion-overskrifter

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 bytecount en uafgjort?
  • I ‘ en lille smule forvirret. Hvilken slags løsning forventer du? Hver løsning skal ” optimeres til testsagerne ” noget, bar skriver en AI, der kan forstå engelsk og har sans for humor. For eksempel registrerer Arnauld ‘ løsning /ly\b/ som kun fungerer, fordi 25 Onio n overskrifter, du valgte, har tilfældigvis flere adverb, men for alt det, ved jeg, at du let kunne slå det op med et andet testbatteri. Og hvem ‘ skal sige, at hans koefficienter ikke er ‘ valgt til at optimere hans score? (Hvorfor ville ‘ ikke optimere dem?)
  • Dette testbatteri virker lidt usædvanligt. Det ‘ er som at bede om en klassificering, der kan registrere hunde på et fotografi, men at tage dine positive testtilfælde som fotos af hunde og dine negative testtilfælde fra en Buzzfeed-artikel med titlen ” 25 fotos af genstande, du ‘ ll sværger, er hunde, men nej, viser sig, at de er ‘ t! (# 11 vil sprænge dit sind!) ” Det gør et svært nok problem sværere.
  • Udfordringen er ikke kun hård, men den er ‘ er også ikke indlysende (for mig) hvad ‘ er forskellen. Hvis jeg ikke kan ‘ ikke løse det, kan mit program selvfølgelig ‘ t løse det (det vil sige, mens det overbeviser mig om, at det ikke ‘ t hardcode til testsagerne)
  • Nå, jeg brugte +36 timer på at træne et kunstigt neuralt netværk ved hjælp af brain.js og LSTM med eksempler i dette nummer og 100 andre prøver af hver type fra leverede links, men resultatet var ‘ t godt nok med nye titler, der ikke var ‘ ikke til stede i træningssæt. Jeg ‘ er færdig: P

Svar

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

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

En simpel heuristisk baseret på længden af titlen, antallet af mellemrum og brug af -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øsning scorede 63,5% på de skjulte testtilfælde, så det er gyldigt.
  • Ikke så simpelt som det var muligt i begyndelsen af sandkassen (100%, ved at bruge forskelle i store bogstaver, før den blev standardiseret), men dette er virkelig simpelt. >
  • @Mego Forbedrer denne NSFW version bare af nysgerrighed scoren på de skjulte testsager? 🙂
  • @Arnauld 66% med den version

Svar

Python 3, 84%

Utestet på skjulte testsager.

Dette bruger Keras LSTM RNN, der er trænet i forskellige overskrifter. For at køre det har du brug for Keras følgende og den model, som jeg har gjort tilgængelig på GitHub: repo link . Du skal bruge modellen .h5 og ord- / vektortilknytningerne er i .pkl. Den seneste

Afhængigheden 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 

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

Nu for at indlæse modellen og ordet embeddings:

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

Og koden for at teste, om en streng er fra “NotTheOnion” eller “TheOnion “Jeg har skrevet en hurtig hjælperfunktion, der konverterer strengen til de respektive ordindlejringer:

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 kode kører en model, der analyserer forholdet mellem ord ved at repræsentere ordene som en “vektor”. Du kan lære mere om ordindlejring her .

Dette trænes i overskrifter, men testsagerne er udelukket .

Disse processer automatiseres efter en hel del behandling. Jeg har distribueret den endelige behandlede ordliste som en .pkl men hvad der sker i ordindlejring er først at vi analyserer sætningen og isolerer ordene.

Efter vi nu har ordene det næste trin er at være i stand til at forstå forskellene og lighederne mellem bestemte ord f.eks. king og queen versus duke og duchess. Disse indlejringer sker ikke mellem de faktiske ord, men mellem tal, der repræsenterer ordene, hvilket er det, der er gemt i .pkl fil. Ord, som maskinen ikke forstår, kortlægges til et specielt ord <UNK>, som giver os mulighed for at forstå, at der er et ord der, men at det ikke vides nøjagtigt, hvad meningen er.

Nu hvor ordene kan forstås, skal ordsekvensen (overskrift) kunne analyseres. Dette er hvad “LSTM” gør, en LTSM er en type “RNN” -celle, som undgår den forsvindende gradienteffekt. Mere simpelt tager det en ordsekvens, og det giver os mulighed for at finde relationer mellem dem.

Nu er det sidste lag Dense hvilket grundlæggende betyder, at det er som en matrix, hvilket betyder, at output er som: [probability_is_not_onion, probability_is_onion]. Ved at finde ud af, hvilken der er større, kan vi vælge, hvilken der er det mest sikre resultat for den givne overskrift.

Svar

Python 3 + Keras, 41/50 = 82%

83% (166/200) på skjulte testsager

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 (meget stor) og her .

Fuldt tilsluttet klassifikator tilsluttet en foruddannet sentimentanalysemodel DeepMoji, som består af stablede tovejs LSTMer og en opmærksom mekanisme. Jeg frøs DeepMoji-lagene og tog det sidste softmax-lag ud, trænede kun de fuldt forbundne lag og frøs så DeepMoji-lagene ud og trænede dem sammen til finjustering. Opmærksomhedsmekanismen er taget fra https://github.com/bfelbo/DeepMoji/blob/master/deepmoji/attlayer.py (jeg ville ikke have brug for al deres kode som en afhængighed for en klasse, især da det er Python 2 og ret uhåndterligt at bruge som et modul …)

Dette fungerer overraskende dårligt på Megos testsæt, i betragtning af at det på min egen større validering er indstillet får> 90%. Så jeg er ikke færdig med dette endnu.

Kommentarer

  • 83% på skjulte testsager, forudsat at jeg kørte det korrekt

Svar

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

96% (192/200) på skjulte testsager

 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 kræver to store JSON-filer, som jeg ikke kan placere dem her eller på ” TiO “. Download dem fra følgende links, og gem dem med words.json og navne, i samme mappe som JS-fil. Der er også et link til en JS-fil med testcases og resultat / procentudskrivning.Du kan placere dine skjulte testtilfælde i onions og nonOnions variabler.

Efter at have gemt alle 3 filer i samme bibliotek, skal du køre node onion.js.

O -funktionen returnerer true hvis det er løg og false hvis det ikke er “t. Bruger en stor liste med ordposer (uden ordre) til at opdage, om inputstrengen er løg. Slags hårdkodet, men fungerer meget godt på en række tilfældige test sager.

Kommentarer

  • Denne løsning får 96% på de skjulte testsager

Svar

Arbejder ud af Arnaulds løsning

JavaScript (ES6), 41/50

64% (128/200) på skjult test tilfælde

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 testsager (ugyldige)

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 

Længde + antal ord + “ly “koncept fungerer ret godt, jeg var i stand til at presse et par flere punkter ud ved at tjekke for ordet” far “(hvornår taler rigtige artikler om folks fædre i tredje person i titlen?) og et yderligere punkt ved at ændre “ly” -søgheuristikken og kontrol af tilstedeværelsen af tal i titlen (hvilket måske er mindre gyldigt i det generelle tilfælde uden for testen, så jeg efterlod begge løsninger)

Kommentarer

  • Jeg kender ikke ‘ ikke kender farens del … virker lidt ligesom at optimere testsagen for mig …
  • Og ja, jeg kan finde masser af Not the Onion-artikler, der nævner dads
  • Der ‘ er sandsynligvis en bedre måde at gøre det som en del af heuristikken og ikke bare en hård ” vinde ” hvis den indeholder far, men jeg forestiller mig, at selv uden for testdatabasen abstrakt taler om en bestemt ” Far ” er mere almindelig på The Onion
  • Din første løsning fik 64% på de skjulte testsager, så den er gyldig. Din anden løsning scorede 62,5% på de skjulte testsager, så den er ikke gyldig.
  • @Mego Hvilken tæt margen …

Skriv et svar

Din e-mailadresse vil ikke blive publiceret. Krævede felter er markeret med *