Bawang, atau Bukan Bawang?

11

Bawang (peringatan: banyak artikel adalah NSFW) adalah organisasi berita satir yang memparodikan media berita tradisional. Pada tahun 2014, The Onion meluncurkan ClickHole (peringatan: juga sering NSFW), situs web berita satir yang memarodikan situs "clickbait" seperti BuzzFeed. Berkat Hukum Poe , cukup umum bagi orang untuk membaca tajuk artikel dari The Onion atau ClickHole dan percaya bahwa itu benar, tidak tahu bahwa itu dimaksudkan untuk sindiran. Kebalikannya juga terjadi dengan berita nyata yang terdengar konyol - orang sering berpikir bahwa mereka satir padahal sebenarnya tidak.

Kebingungan ini secara alami cocok untuk permainan - diberi judul berita, cobalah untuk menebak apakah itu satire atau tidak. Tantangan ini adalah tentang melakukan hal itu dengan sebuah program.

Diberikan judul berita (string yang hanya terdiri dari karakter dan spasi ASCII yang dapat dicetak), ditampilkan 1jika judulnya satire, atau 0jika tidak. Skor Anda akan menjadi jumlah hasil yang benar dibagi dengan jumlah total berita utama.

Seperti biasa, celah standar (terutama optimalisasi untuk kasus uji ) tidak diperbolehkan. Untuk menegakkan ini, saya akan menjalankan program Anda pada 200 kasus tes tersembunyi (100 dari The Onion, 100 dari Not The Onion). Solusi Anda harus skor tidak lebih dari 20 poin persentase kurang dari skor Anda pada kasus uji publik agar valid.

Uji Kasus

Untuk menghasilkan kasus uji untuk tantangan ini, saya mengambil 25 tajuk utama dari The Onion subreddit (di mana artikel dari The Onion dan situs anaknya, seperti ClickHole, diposting), dan 25 tajuk utama dari subreddit Bukan Bawang (di mana artikel berita nyata yang terdengar seperti sindiran diposting). Satu-satunya perubahan yang saya buat pada tajuk utama adalah mengganti tanda kutip "mewah" dengan tanda kutip ASCII reguler dan membakukan kapitalisasi - segala hal lainnya tidak berubah dari tajuk utama artikel asli. Setiap judul ada di barisnya masing-masing.

Judul 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

Bukan berita utama 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
Mego
sumber
6
Your score will be the number of correct outputs divided by the total number of headlinesApakah bytecount merupakan pemutus dasi?
Skidsdev
9
Aku sedikit bingung. Apa jenis solusi yang Anda harapkan? Setiap solusi akan harus "mengoptimalkan untuk kasus-kasus uji" agak, bar menulis AI yang dapat mengerti bahasa Inggris dan memiliki selera humor. Misalnya, solusi Arnauld mendeteksi /ly\b/yang berfungsi hanya karena 25 judul Bawang yang Anda pilih memiliki lebih banyak kata keterangan, tetapi untuk semua yang saya tahu, Anda dapat dengan mudah memasukkannya dengan baterai uji yang berbeda. Dan siapa bilang koefisiennya tidak dipilih untuk mengoptimalkan nilainya? (Kenapa dia tidak mengoptimalkannya?)
Lynn
10
Baterai tes ini memang terlihat agak tidak biasa. Ini seperti meminta pengelompokan yang dapat mendeteksi anjing dalam sebuah foto, tetapi mengambil kasus uji positif Anda sebagai foto anjing dan kasus uji negatif Anda dari artikel Buzzfeed berjudul "25 Foto Objek yang Akan Anda Bersumpah Adalah Anjing, Tapi Tidak, Ternyata Keluar Mereka Tidak! (# 11 Akan Meledakkan Pikiran Anda!) "Itu membuat masalah yang cukup sulit lebih sulit.
Sophia Lechner
4
Tidak hanya tantangannya yang sulit, tetapi juga tidak jelas (bagi saya) apa bedanya. Jika saya tidak bisa menyelesaikannya, tentu saja program saya tidak bisa menyelesaikannya (yaitu, sambil meyakinkan saya bahwa itu tidak hardcode untuk kasus-kasus uji)
user202729
4
Yah saya menghabiskan +36 jam melatih menggunakan jaringan saraf tiruan brain.jsdan LSTM, dengan sampel dalam masalah ini dan 100 sampel lainnya dari setiap jenis dari tautan yang disediakan, tetapi hasilnya tidak cukup baik dengan judul baru yang tidak hadir dalam set pelatihan . Saya sudah selesai: P
Night2

Jawaban:

7

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

63,5% (127/200) pada kasus uji tersembunyi

Heuristik sederhana berdasarkan panjang judul, jumlah spasi, dan penggunaan -lyakhiran.

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

Cobalah online!

Arnauld
sumber
Ini sangat efektif untuk betapa sederhananya itu.
Don Thousand
Solusi ini mencetak 63,5% pada kasus tes tersembunyi, sehingga valid.
Mego
Tidak sesederhana mungkin di awal kotak pasir (100%, memanfaatkan perbedaan kapitalisasi sebelum standar) tetapi ini sangat sederhana.
Zacharý
@Mego Karena penasaran, apakah versi NSFW ini meningkatkan skor pada test case tersembunyi? :)
Arnauld
@Arnauld 66% dengan versi itu
Mego
6

Python 3, 84%

Tidak diuji pada kasus uji tersembunyi.

Ini menggunakan Keras LSTM RNN yang dilatih di berbagai berita utama. Untuk menjalankannya Anda perlu Keras berikut ini dan model yang saya buat tersedia di GitHub: tautan repo . Anda akan membutuhkan model .h5dan pemetaan kata / vektor .pkl. Yang terbaru

Ketergantungannya adalah:

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

Pengaturannya adalah:

max_headline_length = 70
word_count = 20740

Modelnya adalah:

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

Sekarang untuk memuat model dan kata embeddings:

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

Dan kode untuk menguji apakah sebuah string berasal dari 'NotTheOnion' atau 'TheOnion' saya telah menulis fungsi helper cepat yang mengubah string tersebut menjadi kata embeddings masing-masing:

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

Penjelasan

Kode ini menjalankan model yang menganalisis hubungan antara kata-kata dengan menyatakan kata-kata sebagai 'vektor'. Anda dapat mempelajari lebih lanjut tentang penyematan kata di sini .

Ini dilatih di tajuk utama tetapi kasus uji tidak termasuk .

Proses ini otomatis setelah cukup banyak pemrosesan. Saya telah mendistribusikan daftar kata akhir yang diproses sebagai .pkltetapi apa yang terjadi dalam penyematan kata adalah pertama-tama kami menganalisis kalimat dan mengisolasi kata-katanya.

Setelah kita sekarang memiliki kata-kata, langkah selanjutnya adalah untuk dapat memahami perbedaan dan persamaan antara kata-kata tertentu misalnya kingdan queenversus dukedan duchess. Embeddings ini tidak terjadi antara kata-kata yang sebenarnya tetapi antara angka yang mewakili kata-kata yang disimpan dalam .pklfile. Kata-kata yang tidak dimengerti mesin dipetakan ke kata khusus <UNK>yang memungkinkan kita untuk memahami bahwa ada kata di sana tetapi tidak diketahui persis apa artinya.

Sekarang setelah kata-kata tersebut dapat dipahami, urutan kata-kata (informasi utama) harus dapat dianalisis. Inilah yang dilakukan oleh 'LSTM', LTSM adalah jenis sel 'RNN' yang menghindari efek gradien hilang. Lebih sederhana, dibutuhkan urutan kata-kata dan memungkinkan kita untuk menemukan hubungan di antara mereka.

Sekarang lapisan akhir Denseyang pada dasarnya berarti itu jenis seperti sebuah array yang berarti output adalah seperti: [probability_is_not_onion, probability_is_onion]. Dengan menemukan mana yang lebih besar kita dapat memilih mana yang merupakan hasil paling percaya diri untuk tajuk utama yang diberikan.

Downgoat
sumber
3

Python 3 + Keras, 41/50 = 82%

83% (166/200) pada kasus uji tersembunyi

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.h5dan vocabulary.jsondapat diambil dari sini (sangat besar) dan di sini .

Klasifikasi yang terhubung sepenuhnya terhubung ke model analisis sentimen pra-terlatih DeepMoji, yang terdiri dari LSTM dua arah yang ditumpuk dan mekanisme perhatian. Saya membekukan lapisan DeepMoji dan mengeluarkan lapisan softmax terakhir, melatih hanya lapisan yang sepenuhnya terhubung, kemudian membekukan lapisan DeepMoji dan melatihnya bersama untuk finetuning. Mekanisme perhatian diambil dari https://github.com/bfelbo/DeepMoji/blob/master/deepmoji/attlayer.py (saya tidak ingin harus menggunakan semua kode mereka sebagai ketergantungan untuk satu kelas, terutama karena itu Python 2 dan agak sulit digunakan sebagai modul ...)

Ini secara mengejutkan berkinerja buruk pada set pengujian Mego, mengingat pada set validasi saya yang lebih besar, ia mendapat> 90%. Jadi saya belum selesai dengan ini.

sebuah spaghetto
sumber
83% pada kasus tes tersembunyi, dengan asumsi saya menjalankannya dengan benar
Mego
1

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

96% (192/200) pada kasus uji tersembunyi

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

Ini membutuhkan dua file JSON besar yang saya tidak bisa taruh di sini atau di "TiO". Silakan unduh dari tautan berikut dan simpan dengan words.jsondan bags.jsonnama, di folder yang sama dengan file JS. Ada juga tautan untuk file JS dengan kasus uji dan pencetakan hasil / persen. Anda dapat memasukkan kasus uji tersembunyi Anda ke dalam onionsdan nonOnionsvariabel.

Setelah menyimpan ketiga file dalam direktori yang sama, jalankan node onion.js.

The Ofungsi akan kembali truejika bawang dan falsejika tidak. Menggunakan daftar besar kantung kata (tanpa urutan) untuk mendeteksi apakah string input adalah bawang. Agak sulit dikodekan, tetapi bekerja dengan sangat baik pada berbagai kasus uji acak.

Night2
sumber
Solusi ini mendapat 96% pada kasus uji tersembunyi
Mego
0

Mengatasi solusi Arnauld

JavaScript (ES6), 41/50

64% (128/200) pada kasus uji tersembunyi

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) pada kasus uji tersembunyi (tidak valid)

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

Konsep panjang + jumlah kata + "ly" bekerja dengan cukup baik, saya dapat memeras beberapa poin lagi dengan memeriksa kata "Ayah" (kapan artikel nyata berbicara tentang ayah orang-orang sebagai orang ketiga dalam judul?) Dan poin tambahan dengan mengubah heuristik pencarian "ly" dan memeriksa keberadaan angka dalam judul (yang mungkin kurang valid dalam kasus umum di luar tes, jadi saya meninggalkan kedua solusi)

TiKevin83
sumber
Saya tidak tahu tentang bagian ayah ... sepertinya sedikit seperti mengoptimalkan test case kepada saya ...
Don Thousand
Dan ya, saya dapat menemukan banyak artikel Not the Onion yang menyebutkan ayah
Don Thousand
Mungkin ada cara yang lebih baik untuk melakukannya sebagai bagian dari heuristik dan bukan hanya "kemenangan" yang keras jika mengandung ayah, tetapi saya membayangkan bahkan di luar database uji secara abstrak berbicara tentang "Ayah" yang lebih umum pada Bawang
TiKevin83
Solusi pertama Anda mencetak 64% pada kasus uji tersembunyi, jadi itu valid. Solusi kedua Anda memberi skor 62,5% pada kasus uji tersembunyi, sehingga tidak valid.
Mego
@Mego Apa margin yang dekat ...
user202729