{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Understanding Hyperbole using RSA\n", "\n", " \"My new kettle cost a million dollars.\"\n", "\n", "Hyperbole -- using an exagerated utterance to convey strong opinions -- is a common non-literal use of language. Yet non-literal uses of langauge are impossible under the simplest RSA model. Kao, et al, suggested that two ingredients could be added to ennable RSA to capture hyperbole. First, the state conveyed by the speaker and reasoned about by the listener should include affective dimensions. Second, the speaker only intends to convey information relevant to a particular topic, such as \"how expensive was it?\" or \"how am I feeling about the price?\"; pragmatic listeners hence jointly reason about this topic and the state." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "#first some imports\n", "import torch\n", "torch.set_default_dtype(torch.float64) # double precision for numerical stability\n", "\n", "import collections\n", "import argparse\n", "import matplotlib.pyplot as plt\n", "\n", "import pyro\n", "import pyro.distributions as dist\n", "import pyro.poutine as poutine\n", "\n", "from search_inference import HashingMarginal, memoize, Search" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As in the simple RSA example, the inferece helper Marginal takes an un-normalized stochastic function, constructs the distribution over execution traces by using Search, and constructs the marginal distribution on return values (via HashingMarginal)." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "def Marginal(fn):\n", " return memoize(lambda *args: HashingMarginal(Search(fn).run(*args)))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The domain for this example will be states consisting of price (e.g. of a tea kettle) and the speaker's emotional arousal (whether the speaker thinks this price is irritatingly expensive). Priors here are adapted from experimental data." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "State = collections.namedtuple(\"State\", [\"price\", \"arousal\"])\n", "\n", "def price_prior():\n", " values = [50, 51, 500, 501, 1000, 1001, 5000, 5001, 10000, 10001]\n", " probs = torch.tensor([0.4205, 0.3865, 0.0533, 0.0538, 0.0223, 0.0211, 0.0112, 0.0111, 0.0083, 0.0120])\n", " ix = pyro.sample(\"price\", dist.Categorical(probs=probs))\n", " return values[ix]\n", "\n", "def arousal_prior(price):\n", " probs = {\n", " 50: 0.3173,\n", " 51: 0.3173,\n", " 500: 0.7920,\n", " 501: 0.7920,\n", " 1000: 0.8933,\n", " 1001: 0.8933,\n", " 5000: 0.9524,\n", " 5001: 0.9524,\n", " 10000: 0.9864,\n", " 10001: 0.9864\n", " }\n", " return pyro.sample(\"arousal\", dist.Bernoulli(probs=probs[price])).item() == 1\n", "\n", "def state_prior():\n", " price = price_prior()\n", " state = State(price=price, arousal=arousal_prior(price))\n", " return state" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now we define a version of the RSA speaker that only produces *relevant* information for the literal listener. We define relevance with respect to a Question Under Discussion (QUD) -- this can be thought of as defining the speaker's current attention or topic.\n", "\n", "The speaker is defined mathematically by:\n", "\n", "$$P_S(u|s,q) \\propto \\left[ \\sum_{w'} \\delta_{q(w')=q(w)} P_\\text{Lit}(w'|u) p(u) \\right]^\\alpha$$\n", "\n", "To implement this as a probabilistic program, we start with a helper function project, which takes a distribution over some (discrete) domain and a function qud on this domain. It creates the push-forward distribution, using Marginal (as a Python decorator). The speaker's relevant information is then simply information about the state in this projection." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "@Marginal\n", "def project(dist,qud):\n", " v = pyro.sample(\"proj\",dist)\n", " return qud_fns[qud](v)\n", "\n", "@Marginal\n", "def literal_listener(utterance):\n", " state=state_prior()\n", " pyro.factor(\"literal_meaning\", 0. if meaning(utterance, state.price) else -999999.)\n", " return state\n", "\n", "@Marginal\n", "def speaker(state, qud):\n", " alpha = 1.\n", " qudValue = qud_fns[qud](state)\n", " with poutine.scale(scale=torch.tensor(alpha)):\n", " utterance = utterance_prior()\n", " literal_marginal = literal_listener(utterance)\n", " projected_literal = project(literal_marginal, qud)\n", " pyro.sample(\"listener\", projected_literal, obs=qudValue)\n", " return utterance\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The possible QUDs capture that the speaker may be attending to the price, her affect, or some combination of these. We assume a uniform QUD prior." ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "#The QUD functions we consider:\n", "qud_fns = {\n", " \"price\": lambda state: State(price=state.price, arousal=None),\n", " \"arousal\": lambda state: State(price=None, arousal=state.arousal),\n", " \"priceArousal\": lambda state: State(price=state.price, arousal=state.arousal),\n", "}\n", "\n", "def qud_prior():\n", " values = list(qud_fns.keys())\n", " ix = pyro.sample(\"qud\", dist.Categorical(probs=torch.ones(len(values)) / len(values)))\n", " return values[ix]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now we specify the utterance meanings (standard number word denotations: \"N\" means exactly $N$) and a uniform utterance prior. " ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "def utterance_prior():\n", " utterances = [50, 51, 500, 501, 1000, 1001, 5000, 5001, 10000, 10001]\n", " ix = pyro.sample(\"utterance\", dist.Categorical(probs=torch.ones(len(utterances)) / len(utterances)))\n", " return utterances[ix]\n", "\n", "def meaning(utterance, price):\n", " return utterance == price" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "OK, let's see what number term this speaker will say to express different states and QUDs." ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "