Cebula czy nie cebula?


11

Cebula (ostrzeżenie: wiele artykułów to NSFW) to satyryczna organizacja informacyjna, która parodiuje tradycyjne media informacyjne. W 2014 r. The Onion uruchomił ClickHole (ostrzeżenie: również często NSFW), satyryczną witrynę z wiadomościami, która parodiuje witryny typu „clickbait”, takie jak BuzzFeed. Dzięki Prawu Poego ludzie często czytają nagłówki artykułów z The Onion lub ClickHole i wierzą, że to prawda, nie wiedząc, że mają być satyrą. Odwrotna sytuacja zdarza się także w przypadku śmiesznie brzmiących prawdziwych wiadomości - ludzie często myślą, że są satyrami, kiedy tak nie jest.

To zamieszanie w naturalny sposób nadaje się do gry - biorąc pod uwagę nagłówek wiadomości, spróbuj zgadnąć, czy jest to satyra, czy nie. Wyzwanie polega na robieniu tego dokładnie za pomocą programu.

Biorąc pod uwagę nagłówek wiadomości (ciąg składający się wyłącznie z drukowalnych znaków i spacji ASCII), generowany, 1jeśli nagłówek jest satyrą lub 0nie jest. Twój wynik będzie liczbą poprawnych wyników podzieloną przez całkowitą liczbę nagłówków.

Jak zwykle standardowe luki (szczególnie optymalizujące dla przypadków testowych ) są niedozwolone. Aby to wymusić, uruchomię twoje programy na zestawie 200 ukrytych przypadków testowych (100 z The Onion, 100 z Not The Onion). Aby rozwiązanie było ważne, twoje rozwiązanie musi uzyskać nie więcej niż 20 punktów procentowych mniej niż wynik w publicznych testach testowych.

Przypadki testowe

Aby wymyślić przypadki testowe dla tego wyzwania, wybrałem 25 nagłówków z subredditu The Onion (gdzie publikowane są artykuły z The Onion i jego stron podrzędnych, takich jak ClickHole), oraz 25 nagłówków z subredditu Not The Onion (gdzie są prawdziwe artykuły z wiadomościami) brzmi to jak satyra). Jedyne zmiany, które wprowadziłem w nagłówkach, to zastąpienie „fantazyjnych” cytatów zwykłymi cytatami ASCII i ujednolicenie wielkich liter - wszystko inne pozostaje niezmienione od nagłówka oryginalnego artykułu. Każdy nagłówek ma swoją własną linię.

Nagłówki Cebuli

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

Nie nagłówki „The Onion”

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

6
Your score will be the number of correct outputs divided by the total number of headlinesCzy bytecount to remis?
Skidsdev,

9
Jestem trochę zmieszany. Jakiego rodzaju rozwiązania oczekujesz? Każde rozwiązanie będzie musiało „zoptymalizować się pod kątem przypadków testowych”, z wyjątkiem pisania AI, która rozumie angielski i ma poczucie humoru. Na przykład rozwiązanie Arnaulda wykrywa, /ly\b/które działa tylko dlatego, że wybrane przez ciebie nagłówki 25 Cebuli zawierają więcej przysłówków, ale wiem, że możesz łatwo potknąć się przy użyciu innej baterii testowej. A kto ma powiedzieć, że jego współczynniki nie zostały wybrane do optymalizacji jego wyniku? (Dlaczego nie miałby ich zoptymalizować?)
Lynn

10
Ta bateria testowa wydaje się nieco niezwykła. To tak, jakby poprosić o klasyfikatora, który może wykryć psy na zdjęciu, ale przyjmowanie pozytywnych przypadków testowych jako zdjęć psów i negatywnych przypadków testowych z artykułu Buzzfeed zatytułowanego „25 zdjęć obiektów, które przysięgniesz, że są psami, ale nie, zamienia się” Nasze nie są! (# 11 rozwali twój umysł!) "To sprawia, że ​​wystarczająco trudny problem staje się trudniejszy.
Sophia Lechner,

4
Wyzwanie jest nie tylko trudne, ale nie jest dla mnie oczywiste, jaka jest różnica. Jeśli nie mogę go rozwiązać, oczywiście mój program nie może go rozwiązać (to znaczy przekonać mnie, że nie koduje na stałe dla przypadków testowych)
user202729

4
Cóż, spędziłem ponad 36 godzin na szkoleniu sztucznej sieci neuronowej przy użyciu brain.jsi LSTM, z próbkami w tym numerze i 100 innymi próbkami każdego typu z podanych linków, ale wynik nie był wystarczająco dobry z nowymi tytułami, które nie były obecne w zestawach szkoleniowych . Skończyłem: P
Noc 2

Odpowiedzi:


7

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

63,5% (127/200) w przypadku ukrytych przypadków testowych

Prosta heurystyka oparta na długości tytułu, liczbie spacji i użyciu -lysufiksu.

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

Wypróbuj online!


Jest to absurdalnie skuteczne jak proste.
Don Thousand

To rozwiązanie uzyskało 63,5% w przypadku ukrytych przypadków testowych, więc jest prawidłowe.
Mego

Nie tak proste, jak to było możliwe na początku piaskownicy (100%, wykorzystując różnice wielkości liter przed jego standaryzacją), ale jest to naprawdę proste.
Zacharý

@Mego Tylko z ciekawości, czy ta wersja NSFW poprawia wynik w ukrytych testach? :)
Arnauld

@Arnauld 66% z tą wersją
Mego

6

Python 3, 84%

Nie przetestowano na ukrytych przypadkach testowych.

To wykorzystuje Keras LSTM RNN przeszkolony w różnych nagłówkach. Aby go uruchomić, potrzebujesz Keras następującego i modelu, który udostępniłem na GitHub: link repo . Będziesz potrzebował modelu, .h5a mapowania słowo / wektor są w.pkl . Najnowszy

Zależności są następujące:

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

Ustawienia są następujące:

max_headline_length = 70
word_count = 20740

Model to:

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

Teraz, aby załadować model i osadzenie słowa:

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

I kod do sprawdzenia, czy łańcuch pochodzi z „NotTheOnion” lub „TheOnion” Napisałem funkcję szybkiego pomocnika, która konwertuje łańcuch na odpowiednie osadzanie słów:

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

Wyjaśnienie

W tym kodzie działa model, który analizuje związki między słowami, przedstawiając je jako „wektor”. Możesz dowiedzieć się więcej na temat osadzania słów tutaj .

Jest to szkolone w nagłówkach, ale przypadki testowe są wykluczone .

Procesy te są zautomatyzowane po pewnym przetworzeniu. Rozdałem końcową listę przetworzonych słów jako, .pklale to, co dzieje się podczas osadzania słów, najpierw analizujemy zdanie i izolujemy słowa.

Po tym, jak mamy teraz słowa, następnym krokiem jest zrozumienie różnic i podobieństw między niektórymi słowami np. kingI queenversus dukei duchess. Te osadzenia nie zachodzą między rzeczywistymi słowami, ale między liczbami reprezentującymi słowa, które są przechowywane w .pklpliku. Słowa, których maszyna nie rozumie, są odwzorowane na specjalne słowo, <UNK>które pozwala nam zrozumieć, że istnieje tam słowo, ale nie wiadomo dokładnie, jakie jest jego znaczenie.

Teraz, gdy słowa są zrozumiałe, sekwencja słów (nagłówek) musi być analizowana. To właśnie robi „LSTM”, LTSM jest rodzajem komórki „RNN”, która unika efektu zanikającego gradientu. Mówiąc prościej, pobiera sekwencję słów i pozwala nam znaleźć relacje między nimi.

Teraz ostateczna warstwa jest Denseco w zasadzie oznacza, że jest trochę jak tablica oznacza wyjście jest jak: [probability_is_not_onion, probability_is_onion]. Po znalezieniu, który jest większy, możemy wybrać, który jest najbardziej pewnym wynikiem dla danego nagłówka.


3

Python 3 + Keras, 41/50 = 82%

83% (166/200) w przypadku ukrytych przypadków testowych

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.h5i vocabulary.jsonmożna je pobrać stąd (bardzo duże) i tutaj .

W pełni połączony klasyfikator połączony ze wstępnie wyszkolonym modelem analizy sentymentu DeepMoji, który składa się z dwukierunkowych zestawów LSTM i mechanizmu uwagi. Zamroziłem warstwy DeepMoji i wyjąłem ostatnią warstwę softmax, wyszkoliłem tylko w pełni połączone warstwy, a następnie odmroziłem warstwy DeepMoji i wyszkoliłem je razem w celu dostrojenia. Mechanizm uwagi pochodzi z https://github.com/bfelbo/DeepMoji/blob/master/deepmoji/attlayer.py (nie chciałem używać całego ich kodu jako zależności dla jednej klasy, zwłaszcza, że ​​jest to Python 2 i raczej niewygodny do użycia jako moduł ...)

Działa to zaskakująco słabo na zestawie testowym Mego, biorąc pod uwagę, że na moim własnym większym zestawie walidacyjnym dostaje> 90%. Nie skończyłem jeszcze z tym.


83% na ukryte przypadki testowe, przy założeniu, że poprawnie je uruchomiłem
Mego

1

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

96% (192/200) w przypadku ukrytych przypadków testowych

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

Wymaga to dwóch dużych plików JSON, których nie mogę umieścić tutaj ani w „TiO”. Pobierz je z poniższych łączy i zapisz je z nazwami words.jsoni bags.json, w tym samym folderze co plik JS. Istnieje również łącze do pliku JS z przypadkami testowymi i drukowaniem wyniku / procentu. Możesz umieścić swoje ukryte przypadki testoweonions i nonOnionszmienne.

Po zapisaniu wszystkich 3 plików w tym samym katalogu uruchom node onion.js .

OFunkcja zwróci truejeśli jest cebula i falsejeśli tak nie jest. Używa dużej listy worków na słowa (bez kolejności), aby wykryć, czy ciąg wejściowy to cebula. Trochę zakodowane, ale działa bardzo dobrze na różnych przypadkowych przypadkach testowych.


To rozwiązanie otrzymuje 96% ukrytych przypadków testowych
Mego

0

Praca nad rozwiązaniem Arnaulda

JavaScript (ES6), 41/50

64% (128/200) w przypadku ukrytych przypadków testowych

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) w przypadku ukrytych przypadków testowych (nieważne)

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

Koncepcja długość + liczba słów + „ly” działa całkiem dobrze, udało mi się wycisnąć jeszcze kilka punktów, sprawdzając słowo „Tata” (kiedy prawdziwe artykuły mówią o ojcach ludzi w trzeciej osobie w tytule?) I dodatkowy punkt, zmieniając heurystykę wyszukiwania „ly” i sprawdzając obecność liczb w tytule (co może być mniej ważne w ogólnym przypadku poza testem, więc zostawiłem oba rozwiązania)


Nie wiem o części taty ... wydaje mi się to trochę jak optymalizacja przypadku testowego ...
Don Thousand

I tak, mogę znaleźć wiele artykułów Not the Onion o ojcach
Don Thousand

Prawdopodobnie jest lepszy sposób, aby to zrobić w ramach heurystyki, a nie tylko ciężkiej „wygranej”, jeśli zawiera ona tatę, ale wyobrażam sobie, że nawet poza testową bazą danych abstrakcyjne mówienie o konkretnym „ojcu” jest bardziej powszechne w The Onion
TiKevin83

Twoje pierwsze rozwiązanie uzyskało 64% w przypadku ukrytych przypadków testowych, więc jest prawidłowe. Twoje drugie rozwiązanie uzyskało 62,5% w przypadku ukrytych przypadków testowych, więc jest nieważne.
Mego

@Mego What a close margin ...
user202729
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.