# Notebook from joecym/Udacity-ML-Sentiment
Path: Project/SageMaker Project.ipynb

# Creating a Sentiment Analysis Web App
## Using PyTorch and SageMaker

_Deep Learning Nanodegree Program | Deployment_

---

Now that we have a basic understanding of how SageMaker works we will try to use it to construct a complete project from end to end. Our goal will be to have a simple web page which a user can use to enter a movie review. The web page will then send the review off to our deployed model which will predict the sentiment of the entered review.

## Instructions

Some template code has already been provided for you, and you will need to implement additional functionality to successfully complete this notebook. You will not need to modify the included code beyond what is requested. Sections that begin with '**TODO**' in the header indicate that you need to complete or implement some portion within them. Instructions will be provided for each section and the specifics of the implementation are marked in the code block with a `# TODO: ...` comment. Please be sure to read the instructions carefully!

In addition to implementing code, there will be questions for you to answer which relate to the task and your implementation. Each section where you will answer a question is preceded by a '**Question:**' header. Carefully read each question and provide your answer below the '**Answer:**' header by editing the Markdown cell.

> **Note**: Code and Markdown cells can be executed using the **Shift+Enter** keyboard shortcut. In addition, a cell can be edited by typically clicking it (double-click for Markdown cells) or by pressing **Enter** while it is highlighted.

## General Outline

Recall the general outline for SageMaker projects using a notebook instance.

1. Download or otherwise retrieve the data.
2. Process / Prepare the data.
3. Upload the processed data to S3.
4. Train a chosen model.
5. Test the trained model (typically using a batch transform job).
6. Deploy the trained model.
7. Use the deployed model.

For this project, you will be following the steps in the general outline with some modifications.

First, you will not be testing the model in its own step. You will still be testing the model, however, you will do it by deploying your model and then using the deployed model by sending the test data to it. One of the reasons for doing this is so that you can make sure that your deployed model is working correctly before moving forward.

In addition, you will deploy and use your trained model a second time. In the second iteration you will customize the way that your trained model is deployed by including some of your own code. In addition, your newly deployed model will be used in the sentiment analysis web app._____no_output_____## Step 1: Downloading the data

As in the XGBoost in SageMaker notebook, we will be using the [IMDb dataset](http://ai.stanford.edu/~amaas/data/sentiment/)

> Maas, Andrew L., et al. [Learning Word Vectors for Sentiment Analysis](http://ai.stanford.edu/~amaas/data/sentiment/). In _Proceedings of the 49th Annual Meeting of the Association for Computational Linguistics: Human Language Technologies_. Association for Computational Linguistics, 2011._____no_output_____

%mkdir ../data
!wget -O ../data/aclImdb_v1.tar.gz http://ai.stanford.edu/~amaas/data/sentiment/aclImdb_v1.tar.gz
!tar -zxf ../data/aclImdb_v1.tar.gz -C ../datamkdir: cannot create directory ‘../data’: File exists
--2020-07-28 18:16:41--  http://ai.stanford.edu/~amaas/data/sentiment/aclImdb_v1.tar.gz
Resolving ai.stanford.edu (ai.stanford.edu)... 171.64.68.10
Connecting to ai.stanford.edu (ai.stanford.edu)|171.64.68.10|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 84125825 (80M) [application/x-gzip]
Saving to: ‘../data/aclImdb_v1.tar.gz’

../data/aclImdb_v1. 100%[===================>]  80.23M  52.7MB/s    in 1.5s

2020-07-28 18:16:43 (52.7 MB/s) - ‘../data/aclImdb_v1.tar.gz’ saved [84125825/84125825]

## Step 2: Preparing and Processing the data

Also, as in the XGBoost notebook, we will be doing some initial data processing. The first few steps are the same as in the XGBoost example. To begin with, we will read in each of the reviews and combine them into a single input structure. Then, we will split the dataset into a training set and a testing set._____no_output_____

import os
import glob

def read_imdb_data(data_dir='../data/aclImdb'):
    data = {}
    labels = {}

    for data_type in ['train', 'test']:
        data[data_type] = {}
        labels[data_type] = {}

        for sentiment in ['pos', 'neg']:
            data[data_type][sentiment] = []
            labels[data_type][sentiment] = []

            path = os.path.join(data_dir, data_type, sentiment, '*.txt')
            files = glob.glob(path)

            for f in files:
                with open(f) as review:
                    data[data_type][sentiment].append(review.read())
                    # Here we represent a positive review by '1' and a negative review by '0'
                    labels[data_type][sentiment].append(1 if sentiment == 'pos' else 0)

            assert len(data[data_type][sentiment]) == len(labels[data_type][sentiment]), \
                    "{}/{} data size does not match labels size".format(data_type, sentiment)

    return data, labels_____no_output_____data, labels = read_imdb_data()
print("IMDB reviews: train = {} pos / {} neg, test = {} pos / {} neg".format(
            len(data['train']['pos']), len(data['train']['neg']),
            len(data['test']['pos']), len(data['test']['neg'])))IMDB reviews: train = 12500 pos / 12500 neg, test = 12500 pos / 12500 neg

Now that we've read the raw training and testing data from the downloaded dataset, we will combine the positive and negative reviews and shuffle the resulting records._____no_output_____

from sklearn.utils import shuffle

def prepare_imdb_data(data, labels):
    """Prepare training and test sets from IMDb movie reviews."""

    #Combine positive and negative reviews and labels
    data_train = data['train']['pos'] + data['train']['neg']
    data_test = data['test']['pos'] + data['test']['neg']
    labels_train = labels['train']['pos'] + labels['train']['neg']
    labels_test = labels['test']['pos'] + labels['test']['neg']

    #Shuffle reviews and corresponding labels within training and test sets
    data_train, labels_train = shuffle(data_train, labels_train)
    data_test, labels_test = shuffle(data_test, labels_test)

    # Return a unified training data, test data, training labels, test labets
    return data_train, data_test, labels_train, labels_test_____no_output_____train_X, test_X, train_y, test_y = prepare_imdb_data(data, labels)
print("IMDb reviews (combined): train = {}, test = {}".format(len(train_X), len(test_X)))IMDb reviews (combined): train = 25000, test = 25000

Now that we have our training and testing sets unified and prepared, we should do a quick check and see an example of the data our model will be trained on. This is generally a good idea as it allows you to see how each of the further processing steps affects the reviews and it also ensures that the data has been loaded correctly._____no_output_____

print(train_X[100])
print(train_y[100])Absolutely awful movie. Utter waste of time.

background music is so loud that you cannot understand speech. Well if you really listen closely, whatever they speak is actually unintelligible.

Camera work is bad, editing is not present, background score gives a headache, action is shoddy, dialogs are unintelligible, Acting is abysmal and well Kareena used to look like a wrestler, now she looks like a starved wrestler. Hell you can slim down but you cannot gain grace.

After spending three hours watching a movie I want to like it, but this movie would not even allow me that pleasure.

Please if you want to torture yourself, go ahead watch this.
0

The first step in processing the reviews is to make sure that any html tags that appear should be removed. In addition we wish to tokenize our input, that way words such as *entertained* and *entertaining* are considered the same with regard to sentiment analysis._____no_output_____

import nltk
from nltk.corpus import stopwords
from nltk.stem.porter import *

import re
from bs4 import BeautifulSoup

def review_to_words(review):
    nltk.download("stopwords", quiet=True)
    stemmer = PorterStemmer()

    text = BeautifulSoup(review, "html.parser").get_text() # Remove HTML tags
    text = re.sub(r"[^a-zA-Z0-9]", " ", text.lower()) # Convert to lower case
    words = text.split() # Split string into words
    words = [w for w in words if w not in stopwords.words("english")] # Remove stopwords
    words = [PorterStemmer().stem(w) for w in words] # stem

    return words_____no_output_____

The `review_to_words` method defined above uses `BeautifulSoup` to remove any html tags that appear and uses the `nltk` package to tokenize the reviews. As a check to ensure we know how everything is working, try applying `review_to_words` to one of the reviews in the training set._____no_output_____

# TODO: Apply review_to_words to a review (train_X[100] or any other review)

print(review_to_words(train_X[100]))
['absolut', 'aw', 'movi', 'utter', 'wast', 'time', 'background', 'music', 'loud', 'cannot', 'understand', 'speech', 'well', 'realli', 'listen', 'close', 'whatev', 'speak', 'actual', 'unintellig', 'camera', 'work', 'bad', 'edit', 'present', 'background', 'score', 'give', 'headach', 'action', 'shoddi', 'dialog', 'unintellig', 'act', 'abysm', 'well', 'kareena', 'use', 'look', 'like', 'wrestler', 'look', 'like', 'starv', 'wrestler', 'hell', 'slim', 'cannot', 'gain', 'grace', 'spend', 'three', 'hour', 'watch', 'movi', 'want', 'like', 'movi', 'would', 'even', 'allow', 'pleasur', 'pleas', 'want', 'tortur', 'go', 'ahead', 'watch']

**Question:** Above we mentioned that `review_to_words` method removes html formatting and allows us to tokenize the words found in a review, for example, converting *entertained* and *entertaining* into *entertain* so that they are treated as though they are the same word. What else, if anything, does this method do to the input?_____no_output_____**Answer:** It removes stop words and reduces all capitalization. _____no_output_____The method below applies the `review_to_words` method to each of the reviews in the training and testing datasets. In addition it caches the results. This is because performing this processing step can take a long time. This way if you are unable to complete the notebook in the current session, you can come back without needing to process the data a second time._____no_output_____

import pickle

cache_dir = os.path.join("../cache", "sentiment_analysis")  # where to store cache files
os.makedirs(cache_dir, exist_ok=True)  # ensure cache directory exists

def preprocess_data(data_train, data_test, labels_train, labels_test,
                    cache_dir=cache_dir, cache_file="preprocessed_data.pkl"):
    """Convert each review to words; read from cache if available."""

    # If cache_file is not None, try to read from it first
    cache_data = None
    if cache_file is not None:
        try:
            with open(os.path.join(cache_dir, cache_file), "rb") as f:
                cache_data = pickle.load(f)
            print("Read preprocessed data from cache file:", cache_file)
        except:
            pass  # unable to read from cache, but that's okay

    # If cache is missing, then do the heavy lifting
    if cache_data is None:
        # Preprocess training and test data to obtain words for each review
        #words_train = list(map(review_to_words, data_train))
        #words_test = list(map(review_to_words, data_test))
        words_train = [review_to_words(review) for review in data_train]
        words_test = [review_to_words(review) for review in data_test]

        # Write to cache file for future runs
        if cache_file is not None:
            cache_data = dict(words_train=words_train, words_test=words_test,
                              labels_train=labels_train, labels_test=labels_test)
            with open(os.path.join(cache_dir, cache_file), "wb") as f:
                pickle.dump(cache_data, f)
            print("Wrote preprocessed data to cache file:", cache_file)
    else:
        # Unpack data loaded from cache file
        words_train, words_test, labels_train, labels_test = (cache_data['words_train'],
                cache_data['words_test'], cache_data['labels_train'], cache_data['labels_test'])

    return words_train, words_test, labels_train, labels_test_____no_output_____# Preprocess data
train_X, test_X, train_y, test_y = preprocess_data(train_X, test_X, train_y, test_y)Read preprocessed data from cache file: preprocessed_data.pkl

## Transform the data

In the XGBoost notebook we transformed the data from its word representation to a bag-of-words feature representation. For the model we are going to construct in this notebook we will construct a feature representation which is very similar. To start, we will represent each word as an integer. Of course, some of the words that appear in the reviews occur very infrequently and so likely don't contain much information for the purposes of sentiment analysis. The way we will deal with this problem is that we will fix the size of our working vocabulary and we will only include the words that appear most frequently. We will then combine all of the infrequent words into a single category and, in our case, we will label it as `1`.

Since we will be using a recurrent neural network, it will be convenient if the length of each review is the same. To do this, we will fix a size for our reviews and then pad short reviews with the category 'no word' (which we will label `0`) and truncate long reviews._____no_output_____### (TODO) Create a word dictionary

To begin with, we need to construct a way to map words that appear in the reviews to integers. Here we fix the size of our vocabulary (including the 'no word' and 'infrequent' categories) to be `5000` but you may wish to change this to see how it affects the model.

> **TODO:** Complete the implementation for the `build_dict()` method below. Note that even though the vocab_size is set to `5000`, we only want to construct a mapping for the most frequently appearing `4998` words. This is because we want to reserve the special labels `0` for 'no word' and `1` for 'infrequent word'._____no_output_____

import numpy as np

def build_dict(data, vocab_size = 5000):
    """Construct and return a dictionary mapping each of the most frequently appearing words to a unique integer."""

    # TODO: Determine how often each word appears in `data`. Note that `data` is a list of sentences and that a
    #       sentence is a list of words.

    dict_temp = dict()

    for line in data:
        for word in line:
            if word not in dict_temp:
                dict_temp[word]=1
            else:
                dict_temp[word]=dict_temp[word]+1

    # TODO: Sort the words found in `data` so that sorted_words[0] is the most frequently appearing word and
    #       sorted_words[-1] is the least frequently appearing word.

    sorted_words = sorted(dict_temp.items(), key=lambda x: x[1], reverse=True)
    #Citation: https://careerkarma.com/blog/python-sort-a-dictionary-by-value/

    for i, item in enumerate(sorted_words):
        sorted_words[i] = item[0]

    word_dict = {} # This is what we are building, a dictionary that translates words into integers
    for idx, word in enumerate(sorted_words[:vocab_size - 2]): # The -2 is so that we save room for the 'no word'
        word_dict[word] = idx + 2                              # 'infrequent' labels

    return word_dict_____no_output_____

word_dict = build_dict(train_X)
print(word_dict)
len(word_dict){'movi': 2, 'film': 3, 'one': 4, 'like': 5, 'time': 6, 'good': 7, 'make': 8, 'charact': 9, 'get': 10, 'see': 11, 'watch': 12, 'stori': 13, 'even': 14, 'would': 15, 'realli': 16, 'well': 17, 'scene': 18, 'look': 19, 'show': 20, 'much': 21, 'end': 22, 'peopl': 23, 'bad': 24, 'go': 25, 'great': 26, 'also': 27, 'first': 28, 'love': 29, 'think': 30, 'way': 31, 'act': 32, 'play': 33, 'made': 34, 'thing': 35, 'could': 36, 'know': 37, 'say': 38, 'seem': 39, 'work': 40, 'plot': 41, 'two': 42, 'actor': 43, 'year': 44, 'come': 45, 'mani': 46, 'seen': 47, 'take': 48, 'life': 49, 'want': 50, 'never': 51, 'littl': 52, 'best': 53, 'tri': 54, 'man': 55, 'ever': 56, 'give': 57, 'better': 58, 'still': 59, 'perform': 60, 'find': 61, 'feel': 62, 'part': 63, 'back': 64, 'use': 65, 'someth': 66, 'director': 67, 'actual': 68, 'interest': 69, 'lot': 70, 'real': 71, 'old': 72, 'cast': 73, 'though': 74, 'live': 75, 'star': 76, 'enjoy': 77, 'guy': 78, 'anoth': 79, 'new': 80, 'role': 81, 'noth': 82, '10': 83, 'funni': 84, 'music': 85, 'point': 86, 'start': 87, 'set': 88, 'girl': 89, 'origin': 90, 'day': 91, 'world': 92, 'everi': 93, 'believ': 94, 'turn': 95, 'quit': 96, 'direct': 97, 'us': 98, 'thought': 99, 'fact': 100, 'minut': 101, 'horror': 102, 'kill': 103, 'action': 104, 'comedi': 105, 'pretti': 106, 'young': 107, 'wonder': 108, 'happen': 109, 'around': 110, 'got': 111, 'effect': 112, 'right': 113, 'long': 114, 'howev': 115, 'big': 116, 'line': 117, 'famili': 118, 'enough': 119, 'seri': 120, 'may': 121, 'need': 122, 'fan': 123, 'bit': 124, 'script': 125, 'beauti': 126, 'person': 127, 'becom': 128, 'without': 129, 'must': 130, 'alway': 131, 'friend': 132, 'tell': 133, 'reason': 134, 'saw': 135, 'last': 136, 'final': 137, 'kid': 138, 'almost': 139, 'put': 140, 'least': 141, 'sure': 142, 'done': 143, 'whole': 144, 'place': 145, 'complet': 146, 'kind': 147, 'expect': 148, 'differ': 149, 'shot': 150, 'far': 151, 'mean': 152, 'anyth': 153, 'book': 154, 'laugh': 155, 'might': 156, 'name': 157, 'sinc': 158, 'begin': 159, '2': 160, 'probabl': 161, 'woman': 162, 'help': 163, 'entertain': 164, 'let': 165, 'screen': 166, 'call': 167, 'tv': 168, 'moment': 169, 'away': 170, 'read': 171, 'yet': 172, 'rather': 173, 'worst': 174, 'run': 175, 'fun': 176, 'lead': 177, 'hard': 178, 'audienc': 179, 'idea': 180, 'anyon': 181, 'episod': 182, 'american': 183, 'found': 184, 'appear': 185, 'bore': 186, 'especi': 187, 'although': 188, 'hope': 189, 'keep': 190, 'cours': 191, 'anim': 192, 'job': 193, 'goe': 194, 'move': 195, 'sens': 196, 'dvd': 197, 'version': 198, 'war': 199, 'money': 200, 'someon': 201, 'mind': 202, 'mayb': 203, 'problem': 204, 'true': 205, 'hous': 206, 'everyth': 207, 'nice': 208, 'second': 209, 'rate': 210, 'three': 211, 'night': 212, 'face': 213, 'follow': 214, 'recommend': 215, 'main': 216, 'product': 217, 'worth': 218, 'leav': 219, 'human': 220, 'special': 221, 'excel': 222, 'togeth': 223, 'wast': 224, 'everyon': 225, 'sound': 226, 'john': 227, 'hand': 228, '1': 229, 'father': 230, 'later': 231, 'eye': 232, 'said': 233, 'view': 234, 'instead': 235, 'review': 236, 'boy': 237, 'high': 238, 'hour': 239, 'miss': 240, 'classic': 241, 'talk': 242, 'wife': 243, 'understand': 244, 'left': 245, 'care': 246, 'black': 247, 'death': 248, 'open': 249, 'murder': 250, 'write': 251, 'half': 252, 'head': 253, 'rememb': 254, 'chang': 255, 'viewer': 256, 'fight': 257, 'gener': 258, 'surpris': 259, 'includ': 260, 'short': 261, 'die': 262, 'fall': 263, 'less': 264, 'els': 265, 'entir': 266, 'piec': 267, 'involv': 268, 'pictur': 269, 'simpli': 270, 'home': 271, 'power': 272, 'top': 273, 'total': 274, 'usual': 275, 'budget': 276, 'attempt': 277, 'suppos': 278, 'releas': 279, 'hollywood': 280, 'terribl': 281, 'song': 282, 'men': 283, 'possibl': 284, 'featur': 285, 'portray': 286, 'disappoint': 287, '3': 288, 'poor': 289, 'coupl': 290, 'stupid': 291, 'camera': 292, 'dead': 293, 'wrong': 294, 'low': 295, 'produc': 296, 'either': 297, 'video': 298, 'aw': 299, 'definit': 300, 'except': 301, 'rest': 302, 'given': 303, 'absolut': 304, 'women': 305, 'lack': 306, 'word': 307, 'writer': 308, 'titl': 309, 'talent': 310, 'decid': 311, 'full': 312, 'perfect': 313, 'along': 314, 'style': 315, 'close': 316, 'truli': 317, 'school': 318, 'save': 319, 'emot': 320, 'age': 321, 'sex': 322, 'next': 323, 'bring': 324, 'mr': 325, 'case': 326, 'killer': 327, 'heart': 328, 'comment': 329, 'sort': 330, 'creat': 331, 'perhap': 332, 'came': 333, 'brother': 334, 'sever': 335, 'joke': 336, 'art': 337, 'dialogu': 338, 'game': 339, 'small': 340, 'base': 341, 'flick': 342, 'written': 343, 'sequenc': 344, 'meet': 345, 'earli': 346, 'often': 347, 'other': 348, 'mother': 349, 'develop': 350, 'humor': 351, 'actress': 352, 'consid': 353, 'dark': 354, 'guess': 355, 'amaz': 356, 'unfortun': 357, 'lost': 358, 'light': 359, 'exampl': 360, 'cinema': 361, 'drama': 362, 'ye': 363, 'white': 364, 'experi': 365, 'imagin': 366, 'mention': 367, 'stop': 368, 'natur': 369, 'forc': 370, 'manag': 371, 'felt': 372, 'present': 373, 'cut': 374, 'children': 375, 'fail': 376, 'son': 377, 'support': 378, 'qualiti': 379, 'car': 380, 'ask': 381, 'hit': 382, 'side': 383, 'voic': 384, 'extrem': 385, 'impress': 386, 'wors': 387, 'evil': 388, 'went': 389, 'stand': 390, 'certainli': 391, 'basic': 392, 'oh': 393, 'overal': 394, 'favorit': 395, 'horribl': 396, 'mysteri': 397, 'number': 398, 'type': 399, 'danc': 400, 'wait': 401, 'hero': 402, 'alreadi': 403, '5': 404, 'learn': 405, 'matter': 406, '4': 407, 'michael': 408, 'genr': 409, 'fine': 410, 'despit': 411, 'throughout': 412, 'walk': 413, 'success': 414, 'histori': 415, 'question': 416, 'zombi': 417, 'town': 418, 'realiz': 419, 'relationship': 420, 'child': 421, 'past': 422, 'daughter': 423, 'late': 424, 'b': 425, 'wish': 426, 'hate': 427, 'credit': 428, 'event': 429, 'theme': 430, 'touch': 431, 'citi': 432, 'today': 433, 'sometim': 434, 'behind': 435, 'god': 436, 'twist': 437, 'sit': 438, 'deal': 439, 'annoy': 440, 'stay': 441, 'abl': 442, 'rent': 443, 'pleas': 444, 'edit': 445, 'blood': 446, 'deserv': 447, 'anyway': 448, 'comic': 449, 'appar': 450, 'soon': 451, 'gave': 452, 'etc': 453, 'level': 454, 'slow': 455, 'chanc': 456, 'score': 457, 'bodi': 458, 'brilliant': 459, 'incred': 460, 'figur': 461, 'situat': 462, 'self': 463, 'major': 464, 'stuff': 465, 'decent': 466, 'element': 467, 'return': 468, 'dream': 469, 'obvious': 470, 'continu': 471, 'order': 472, 'pace': 473, 'ridicul': 474, 'happi': 475, 'add': 476, 'highli': 477, 'group': 478, 'thank': 479, 'ladi': 480, 'novel': 481, 'speak': 482, 'pain': 483, 'career': 484, 'shoot': 485, 'strang': 486, 'heard': 487, 'sad': 488, 'husband': 489, 'polic': 490, 'import': 491, 'break': 492, 'took': 493, 'strong': 494, 'cannot': 495, 'predict': 496, 'robert': 497, 'violenc': 498, 'hilari': 499, 'recent': 500, 'countri': 501, 'known': 502, 'particularli': 503, 'pick': 504, 'documentari': 505, 'season': 506, 'critic': 507, 'jame': 508, 'compar': 509, 'obviou': 510, 'alon': 511, 'told': 512, 'state': 513, 'visual': 514, 'rock': 515, 'offer': 516, 'exist': 517, 'theater': 518, 'opinion': 519, 'gore': 520, 'hold': 521, 'crap': 522, 'result': 523, 'hear': 524, 'room': 525, 'realiti': 526, 'clich': 527, 'effort': 528, 'thriller': 529, 'caus': 530, 'serious': 531, 'sequel': 532, 'explain': 533, 'king': 534, 'local': 535, 'ago': 536, 'hell': 537, 'none': 538, 'note': 539, 'allow': 540, 'sister': 541, 'david': 542, 'simpl': 543, 'femal': 544, 'deliv': 545, 'ok': 546, 'convinc': 547, 'class': 548, 'check': 549, 'suspens': 550, 'win': 551, 'oscar': 552, 'buy': 553, 'huge': 554, 'valu': 555, 'sexual': 556, 'scari': 557, 'cool': 558, 'excit': 559, 'similar': 560, 'apart': 561, 'exactli': 562, 'provid': 563, 'avoid': 564, 'shown': 565, 'seriou': 566, 'english': 567, 'whose': 568, 'taken': 569, 'cinematographi': 570, 'shock': 571, 'polit': 572, 'spoiler': 573, 'offic': 574, 'across': 575, 'middl': 576, 'pass': 577, 'street': 578, 'messag': 579, 'charm': 580, 'silli': 581, 'somewhat': 582, 'modern': 583, 'filmmak': 584, 'confus': 585, 'form': 586, 'tale': 587, 'singl': 588, 'jack': 589, 'mostli': 590, 'carri': 591, 'attent': 592, 'william': 593, 'sing': 594, 'five': 595, 'subject': 596, 'prove': 597, 'richard': 598, 'team': 599, 'stage': 600, 'unlik': 601, 'cop': 602, 'georg': 603, 'televis': 604, 'monster': 605, 'earth': 606, 'villain': 607, 'cover': 608, 'pay': 609, 'marri': 610, 'toward': 611, 'build': 612, 'pull': 613, 'parent': 614, 'due': 615, 'respect': 616, 'fill': 617, 'four': 618, 'dialog': 619, 'remind': 620, 'futur': 621, 'typic': 622, 'weak': 623, '7': 624, 'cheap': 625, 'intellig': 626, 'atmospher': 627, 'british': 628, 'clearli': 629, '80': 630, 'paul': 631, 'dog': 632, 'non': 633, 'artist': 634, '8': 635, 'knew': 636, 'fast': 637, 'crime': 638, 'easili': 639, 'escap': 640, 'adult': 641, 'doubt': 642, 'detail': 643, 'date': 644, 'romant': 645, 'member': 646, 'fire': 647, 'drive': 648, 'gun': 649, 'straight': 650, 'fit': 651, 'beyond': 652, 'attack': 653, 'imag': 654, 'upon': 655, 'posit': 656, 'whether': 657, 'fantast': 658, 'peter': 659, 'appreci': 660, 'captur': 661, 'aspect': 662, 'ten': 663, 'plan': 664, 'discov': 665, 'remain': 666, 'period': 667, 'near': 668, 'air': 669, 'realist': 670, 'mark': 671, 'red': 672, 'dull': 673, 'adapt': 674, 'within': 675, 'lose': 676, 'spend': 677, 'materi': 678, 'color': 679, 'chase': 680, 'mari': 681, 'storylin': 682, 'forget': 683, 'bunch': 684, 'clear': 685, 'lee': 686, 'victim': 687, 'nearli': 688, 'box': 689, 'york': 690, 'match': 691, 'inspir': 692, 'finish': 693, 'mess': 694, 'standard': 695, 'easi': 696, 'truth': 697, 'suffer': 698, 'busi': 699, 'bill': 700, 'space': 701, 'dramat': 702, 'western': 703, 'e': 704, 'list': 705, 'battl': 706, 'notic': 707, 'de': 708, 'french': 709, 'ad': 710, '9': 711, 'tom': 712, 'larg': 713, 'among': 714, 'eventu': 715, 'accept': 716, 'train': 717, 'agre': 718, 'spirit': 719, 'soundtrack': 720, 'third': 721, 'teenag': 722, 'soldier': 723, 'adventur': 724, 'suggest': 725, 'famou': 726, 'drug': 727, 'sorri': 728, 'babi': 729, 'cri': 730, 'normal': 731, 'troubl': 732, 'ultim': 733, 'contain': 734, 'certain': 735, 'cultur': 736, 'romanc': 737, 'rare': 738, 'lame': 739, 'somehow': 740, 'mix': 741, 'disney': 742, 'gone': 743, 'cartoon': 744, 'student': 745, 'reveal': 746, 'fear': 747, 'kept': 748, 'suck': 749, 'attract': 750, 'appeal': 751, 'premis': 752, 'secret': 753, 'design': 754, 'greatest': 755, 'shame': 756, 'throw': 757, 'copi': 758, 'scare': 759, 'wit': 760, 'america': 761, 'admit': 762, 'brought': 763, 'particular': 764, 'relat': 765, 'screenplay': 766, 'whatev': 767, 'pure': 768, '70': 769, 'harri': 770, 'averag': 771, 'master': 772, 'describ': 773, 'male': 774, 'treat': 775, '20': 776, 'fantasi': 777, 'issu': 778, 'warn': 779, 'inde': 780, 'background': 781, 'forward': 782, 'project': 783, 'free': 784, 'memor': 785, 'japanes': 786, 'poorli': 787, 'award': 788, 'locat': 789, 'potenti': 790, 'amus': 791, 'struggl': 792, 'magic': 793, 'weird': 794, 'societi': 795, 'okay': 796, 'imdb': 797, 'doctor': 798, 'accent': 799, 'water': 800, 'hot': 801, 'dr': 802, 'alien': 803, 'express': 804, '30': 805, 'odd': 806, 'crazi': 807, 'choic': 808, 'fiction': 809, 'studio': 810, 'control': 811, 'becam': 812, 'masterpiec': 813, 'difficult': 814, 'fli': 815, 'joe': 816, 'scream': 817, 'costum': 818, 'lover': 819, 'refer': 820, 'uniqu': 821, 'remak': 822, 'girlfriend': 823, 'vampir': 824, 'prison': 825, 'execut': 826, 'wear': 827, 'jump': 828, 'unless': 829, 'wood': 830, 'creepi': 831, 'cheesi': 832, 'superb': 833, 'otherwis': 834, 'parti': 835, 'ghost': 836, 'roll': 837, 'mad': 838, 'public': 839, 'depict': 840, 'jane': 841, 'earlier': 842, 'badli': 843, 'week': 844, 'moral': 845, 'dumb': 846, 'fi': 847, 'flaw': 848, 'grow': 849, 'deep': 850, 'sci': 851, 'maker': 852, 'cat': 853, 'connect': 854, 'older': 855, 'footag': 856, 'plenti': 857, 'bother': 858, 'outsid': 859, 'stick': 860, 'gay': 861, 'catch': 862, 'plu': 863, 'co': 864, 'popular': 865, 'equal': 866, 'social': 867, 'disturb': 868, 'quickli': 869, 'perfectli': 870, 'dress': 871, 'era': 872, '90': 873, 'mistak': 874, 'lie': 875, 'ride': 876, 'previou': 877, 'combin': 878, 'concept': 879, 'band': 880, 'rich': 881, 'surviv': 882, 'answer': 883, 'front': 884, 'sweet': 885, 'christma': 886, 'insid': 887, 'concern': 888, 'bare': 889, 'eat': 890, 'listen': 891, 'ben': 892, 'beat': 893, 'c': 894, 'serv': 895, 'term': 896, 'la': 897, 'german': 898, 'meant': 899, 'stereotyp': 900, 'hardli': 901, 'law': 902, 'innoc': 903, 'desper': 904, 'promis': 905, 'memori': 906, 'cute': 907, 'intent': 908, 'variou': 909, 'inform': 910, 'steal': 911, 'brain': 912, 'post': 913, 'tone': 914, 'island': 915, 'amount': 916, 'track': 917, 'nuditi': 918, 'compani': 919, 'store': 920, 'claim': 921, 'hair': 922, 'flat': 923, '50': 924, 'univers': 925, 'land': 926, 'scott': 927, 'fairli': 928, 'danger': 929, 'kick': 930, 'player': 931, 'step': 932, 'plain': 933, 'crew': 934, 'toni': 935, 'share': 936, 'centuri': 937, 'tast': 938, 'engag': 939, 'achiev': 940, 'travel': 941, 'cold': 942, 'suit': 943, 'rip': 944, 'record': 945, 'manner': 946, 'sadli': 947, 'tension': 948, 'spot': 949, 'wrote': 950, 'fascin': 951, 'intens': 952, 'familiar': 953, 'burn': 954, 'depth': 955, 'remark': 956, 'destroy': 957, 'histor': 958, 'sleep': 959, 'purpos': 960, 'languag': 961, 'ignor': 962, 'ruin': 963, 'delight': 964, 'italian': 965, 'unbeliev': 966, 'abil': 967, 'collect': 968, 'soul': 969, 'detect': 970, 'clever': 971, 'violent': 972, 'rape': 973, 'reach': 974, 'door': 975, 'liter': 976, 'trash': 977, 'scienc': 978, 'caught': 979, 'commun': 980, 'reveng': 981, 'creatur': 982, 'approach': 983, 'trip': 984, 'fashion': 985, 'intrigu': 986, 'skill': 987, 'paint': 988, 'introduc': 989, 'channel': 990, 'complex': 991, 'camp': 992, 'christian': 993, 'extra': 994, 'hole': 995, 'immedi': 996, 'limit': 997, 'ann': 998, 'mental': 999, 'slightli': 1000, '6': 1001, 'million': 1002, 'mere': 1003, 'comput': 1004, 'slasher': 1005, 'conclus': 1006, 'imposs': 1007, 'suddenli': 1008, 'neither': 1009, 'teen': 1010, 'crimin': 1011, 'spent': 1012, 'physic': 1013, 'nation': 1014, 'respons': 1015, 'planet': 1016, 'receiv': 1017, 'fake': 1018, 'sick': 1019, 'blue': 1020, 'bizarr': 1021, 'embarrass': 1022, 'indian': 1023, '15': 1024, 'ring': 1025, 'drop': 1026, 'pop': 1027, 'drag': 1028, 'haunt': 1029, 'pointless': 1030, 'suspect': 1031, 'search': 1032, 'edg': 1033, 'handl': 1034, 'common': 1035, 'biggest': 1036, 'hurt': 1037, 'faith': 1038, 'arriv': 1039, 'technic': 1040, 'angel': 1041, 'dad': 1042, 'genuin': 1043, 'awesom': 1044, 'solid': 1045, 'f': 1046, 'former': 1047, 'colleg': 1048, 'van': 1049, 'focu': 1050, 'count': 1051, 'tear': 1052, 'heavi': 1053, 'rais': 1054, 'wall': 1055, 'younger': 1056, 'laughabl': 1057, 'visit': 1058, 'sign': 1059, 'excus': 1060, 'fair': 1061, 'cult': 1062, 'tough': 1063, 'key': 1064, 'motion': 1065, 'super': 1066, 'desir': 1067, 'stun': 1068, 'addit': 1069, 'exploit': 1070, 'cloth': 1071, 'smith': 1072, 'tortur': 1073, 'davi': 1074, 'race': 1075, 'author': 1076, 'cross': 1077, 'jim': 1078, 'consist': 1079, 'focus': 1080, 'minor': 1081, 'compel': 1082, 'pathet': 1083, 'commit': 1084, 'chemistri': 1085, 'park': 1086, 'frank': 1087, 'tradit': 1088, 'obsess': 1089, 'grade': 1090, 'asid': 1091, '60': 1092, 'brutal': 1093, 'somewher': 1094, 'steve': 1095, 'grant': 1096, 'rule': 1097, 'u': 1098, 'depress': 1099, 'explor': 1100, 'opportun': 1101, 'honest': 1102, 'besid': 1103, 'dub': 1104, 'anti': 1105, 'trailer': 1106, 'intend': 1107, 'bar': 1108, 'regard': 1109, 'longer': 1110, 'west': 1111, 'scientist': 1112, 'judg': 1113, 'decad': 1114, 'silent': 1115, 'armi': 1116, 'creativ': 1117, 'wild': 1118, 'stewart': 1119, 'g': 1120, 'south': 1121, 'draw': 1122, 'road': 1123, 'govern': 1124, 'ex': 1125, 'boss': 1126, 'practic': 1127, 'club': 1128, 'gang': 1129, 'motiv': 1130, 'festiv': 1131, 'surprisingli': 1132, 'london': 1133, 'green': 1134, 'redeem': 1135, 'page': 1136, 'aliv': 1137, 'militari': 1138, 'idiot': 1139, 'machin': 1140, 'display': 1141, 'thrill': 1142, 'repeat': 1143, 'folk': 1144, 'yeah': 1145, '100': 1146, 'nobodi': 1147, '40': 1148, 'garbag': 1149, 'journey': 1150, 'ground': 1151, 'smile': 1152, 'tire': 1153, 'bought': 1154, 'mood': 1155, 'cost': 1156, 'stone': 1157, 'sam': 1158, 'noir': 1159, 'mouth': 1160, 'terrif': 1161, 'agent': 1162, 'utterli': 1163, 'requir': 1164, 'honestli': 1165, 'sexi': 1166, 'area': 1167, 'geniu': 1168, 'report': 1169, 'humour': 1170, 'glad': 1171, 'enter': 1172, 'investig': 1173, 'serial': 1174, 'passion': 1175, 'occasion': 1176, 'narr': 1177, 'marriag': 1178, 'climax': 1179, 'studi': 1180, 'industri': 1181, 'demon': 1182, 'ship': 1183, 'nowher': 1184, 'center': 1185, 'charli': 1186, 'hors': 1187, 'bear': 1188, 'loos': 1189, 'hang': 1190, 'wow': 1191, 'graphic': 1192, 'giant': 1193, 'admir': 1194, 'send': 1195, 'loud': 1196, 'damn': 1197, 'rel': 1198, 'profession': 1199, 'nake': 1200, 'subtl': 1201, 'blow': 1202, 'bottom': 1203, 'batman': 1204, 'insult': 1205, 'doubl': 1206, 'r': 1207, 'boyfriend': 1208, 'kelli': 1209, 'initi': 1210, 'frame': 1211, 'opera': 1212, 'gem': 1213, 'cinemat': 1214, 'drawn': 1215, 'affect': 1216, 'church': 1217, 'challeng': 1218, 'l': 1219, 'seek': 1220, 'fulli': 1221, 'j': 1222, 'nightmar': 1223, 'evid': 1224, 'essenti': 1225, 'conflict': 1226, 'arm': 1227, 'henri': 1228, 'christoph': 1229, 'grace': 1230, 'wind': 1231, 'assum': 1232, 'narrat': 1233, 'witch': 1234, 'push': 1235, 'hunt': 1236, 'wise': 1237, 'chri': 1238, 'month': 1239, 'repres': 1240, 'nomin': 1241, 'sceneri': 1242, 'hide': 1243, 'affair': 1244, 'avail': 1245, 'thu': 1246, 'justic': 1247, 'smart': 1248, 'bond': 1249, 'outstand': 1250, 'flashback': 1251, 'interview': 1252, 'constantli': 1253, 'presenc': 1254, 'satisfi': 1255, 'bed': 1256, 'central': 1257, 'iron': 1258, 'sell': 1259, 'content': 1260, 'everybodi': 1261, 'gag': 1262, 'hotel': 1263, 'slowli': 1264, 'hire': 1265, 'system': 1266, 'individu': 1267, 'thrown': 1268, 'adam': 1269, 'charl': 1270, 'hey': 1271, 'mediocr': 1272, 'allen': 1273, 'jone': 1274, 'ray': 1275, 'lesson': 1276, 'billi': 1277, 'photographi': 1278, 'cameo': 1279, 'pari': 1280, 'fellow': 1281, 'strike': 1282, 'rise': 1283, 'independ': 1284, 'absurd': 1285, 'brief': 1286, 'neg': 1287, 'phone': 1288, 'impact': 1289, 'model': 1290, 'ill': 1291, 'born': 1292, 'fresh': 1293, 'spoil': 1294, 'angl': 1295, 'likabl': 1296, 'abus': 1297, 'discuss': 1298, 'hill': 1299, 'ahead': 1300, 'sight': 1301, 'photograph': 1302, 'sent': 1303, 'logic': 1304, 'occur': 1305, 'blame': 1306, 'shine': 1307, 'bruce': 1308, 'mainli': 1309, 'forev': 1310, 'skip': 1311, 'commerci': 1312, 'held': 1313, 'surround': 1314, 'teacher': 1315, 'segment': 1316, 'zero': 1317, 'blond': 1318, 'summer': 1319, 'satir': 1320, 'trap': 1321, 'resembl': 1322, 'ball': 1323, 'six': 1324, 'queen': 1325, 'fool': 1326, 'sub': 1327, 'tragedi': 1328, 'twice': 1329, 'pack': 1330, 'reaction': 1331, 'bomb': 1332, 'hospit': 1333, 'will': 1334, 'protagonist': 1335, 'sport': 1336, 'mile': 1337, 'trust': 1338, 'drink': 1339, 'vote': 1340, 'mom': 1341, 'jerri': 1342, 'encount': 1343, 'plane': 1344, 'current': 1345, 'al': 1346, 'program': 1347, 'station': 1348, 'choos': 1349, 'martin': 1350, 'celebr': 1351, 'join': 1352, 'round': 1353, 'field': 1354, 'lord': 1355, 'favourit': 1356, 'tragic': 1357, 'jean': 1358, 'robot': 1359, 'vision': 1360, 'tie': 1361, 'arthur': 1362, 'fortun': 1363, 'roger': 1364, 'random': 1365, 'dread': 1366, 'intern': 1367, 'psycholog': 1368, 'improv': 1369, 'epic': 1370, 'nonsens': 1371, 'prefer': 1372, 'pleasur': 1373, 'highlight': 1374, 'formula': 1375, 'legend': 1376, 'tape': 1377, '11': 1378, 'dollar': 1379, 'wide': 1380, 'gorgeou': 1381, 'porn': 1382, 'fox': 1383, 'thin': 1384, 'object': 1385, 'buddi': 1386, 'influenc': 1387, 'ugli': 1388, 'ii': 1389, 'prepar': 1390, 'nasti': 1391, 'reflect': 1392, 'supposedli': 1393, 'warm': 1394, 'progress': 1395, 'worthi': 1396, 'youth': 1397, 'latter': 1398, 'length': 1399, 'unusu': 1400, 'crash': 1401, 'superior': 1402, 'childhood': 1403, 'seven': 1404, 'shop': 1405, 'theatr': 1406, 'remot': 1407, 'paid': 1408, 'pilot': 1409, 'funniest': 1410, 'disgust': 1411, 'castl': 1412, 'trick': 1413, 'fell': 1414, 'convers': 1415, 'establish': 1416, 'rob': 1417, 'gangster': 1418, 'disast': 1419, 'ident': 1420, 'mine': 1421, 'disappear': 1422, 'heaven': 1423, 'suicid': 1424, 'heroin': 1425, 'forgotten': 1426, 'singer': 1427, 'mask': 1428, 'tend': 1429, 'decis': 1430, 'brian': 1431, 'partner': 1432, 'alan': 1433, 'recogn': 1434, 'desert': 1435, 'thoroughli': 1436, 'p': 1437, 'stuck': 1438, 'sky': 1439, 'ms': 1440, 'replac': 1441, 'accur': 1442, 'market': 1443, 'commentari': 1444, 'seemingli': 1445, 'eddi': 1446, 'andi': 1447, 'clue': 1448, 'danni': 1449, 'uncl': 1450, 'devil': 1451, 'jackson': 1452, 'pair': 1453, 'that': 1454, 'therefor': 1455, 'refus': 1456, 'accid': 1457, 'fault': 1458, 'fate': 1459, 'unit': 1460, 'ed': 1461, 'river': 1462, 'afraid': 1463, 'tune': 1464, 'clean': 1465, 'russian': 1466, 'stephen': 1467, 'hidden': 1468, 'irrit': 1469, 'instanc': 1470, 'readi': 1471, 'captain': 1472, 'quick': 1473, 'convey': 1474, 'test': 1475, 'european': 1476, 'frustrat': 1477, 'daniel': 1478, 'insan': 1479, 'chines': 1480, 'wed': 1481, 'rescu': 1482, '1950': 1483, 'food': 1484, 'lock': 1485, 'angri': 1486, 'dirti': 1487, 'joy': 1488, 'price': 1489, 'steven': 1490, 'cage': 1491, 'bland': 1492, 'rang': 1493, 'anymor': 1494, 'wooden': 1495, 'news': 1496, 'jason': 1497, 'rush': 1498, 'n': 1499, 'twenti': 1500, 'board': 1501, 'worri': 1502, 'martial': 1503, '12': 1504, 'led': 1505, 'hunter': 1506, 'transform': 1507, 'cgi': 1508, 'symbol': 1509, 'sentiment': 1510, 'x': 1511, 'onto': 1512, 'invent': 1513, 'piti': 1514, 'johnni': 1515, 'process': 1516, 'explan': 1517, 'attitud': 1518, 'awar': 1519, 'owner': 1520, 'aim': 1521, 'floor': 1522, 'target': 1523, 'favor': 1524, 'necessari': 1525, 'energi': 1526, 'opposit': 1527, 'religi': 1528, 'insight': 1529, 'chick': 1530, 'window': 1531, 'blind': 1532, 'movement': 1533, 'mountain': 1534, 'possess': 1535, 'research': 1536, 'deepli': 1537, 'comparison': 1538, 'comed': 1539, 'whatsoev': 1540, 'grand': 1541, 'rain': 1542, 'began': 1543, 'shadow': 1544, 'bank': 1545, 'mid': 1546, 'parodi': 1547, 'princ': 1548, 'friendship': 1549, 'credibl': 1550, 'pre': 1551, 'taylor': 1552, 'weapon': 1553, 'teach': 1554, 'flesh': 1555, 'dougla': 1556, 'protect': 1557, 'bloodi': 1558, 'hint': 1559, 'terror': 1560, 'marvel': 1561, 'accord': 1562, 'watchabl': 1563, 'anybodi': 1564, 'leader': 1565, 'drunk': 1566, 'superman': 1567, 'load': 1568, 'brown': 1569, 'freddi': 1570, 'jeff': 1571, 'tim': 1572, 'appropri': 1573, 'seat': 1574, 'hitler': 1575, 'villag': 1576, 'charg': 1577, 'unknown': 1578, 'knock': 1579, 'keaton': 1580, 'unnecessari': 1581, 'media': 1582, 'empti': 1583, 'enemi': 1584, 'england': 1585, 'utter': 1586, 'strength': 1587, 'dare': 1588, 'perspect': 1589, 'craft': 1590, 'wave': 1591, 'buck': 1592, 'kiss': 1593, 'contrast': 1594, 'correct': 1595, 'ford': 1596, 'nativ': 1597, 'distract': 1598, 'soap': 1599, 'anywher': 1600, 'knowledg': 1601, 'speed': 1602, 'magnific': 1603, 'nazi': 1604, 'chill': 1605, 'mission': 1606, 'ice': 1607, '1980': 1608, 'breath': 1609, 'fred': 1610, 'crowd': 1611, 'jr': 1612, 'joan': 1613, 'moon': 1614, 'frighten': 1615, '000': 1616, 'soft': 1617, 'kate': 1618, 'nick': 1619, 'dan': 1620, 'dick': 1621, 'hundr': 1622, 'dozen': 1623, 'radio': 1624, 'simon': 1625, 'somebodi': 1626, 'shakespear': 1627, 'andrew': 1628, 'thousand': 1629, 'academi': 1630, 'loss': 1631, 'sum': 1632, 'root': 1633, 'quot': 1634, 'account': 1635, 'vehicl': 1636, 'convent': 1637, 'behavior': 1638, 'leg': 1639, '1970': 1640, 'gold': 1641, 'regular': 1642, 'demand': 1643, 'pretenti': 1644, 'worker': 1645, 'compet': 1646, 'interpret': 1647, 'privat': 1648, 'explos': 1649, 'lynch': 1650, 'stretch': 1651, 'candi': 1652, 'notabl': 1653, 'japan': 1654, 'constant': 1655, 'debut': 1656, 'tarzan': 1657, 'spi': 1658, 'revolv': 1659, 'translat': 1660, 'prais': 1661, 'sea': 1662, 'ass': 1663, 'franc': 1664, 'quiet': 1665, 'threaten': 1666, 'jesu': 1667, 'sat': 1668, 'failur': 1669, 'technolog': 1670, 'aid': 1671, 'kevin': 1672, 'punch': 1673, 'met': 1674, 'toy': 1675, 'higher': 1676, 'vh': 1677, 'interact': 1678, 'abandon': 1679, 'mike': 1680, 'separ': 1681, 'bet': 1682, 'command': 1683, 'confront': 1684, 'recal': 1685, 'gotten': 1686, 'techniqu': 1687, 'site': 1688, 'stunt': 1689, 'belong': 1690, 'servic': 1691, 'cabl': 1692, 'freak': 1693, 'foot': 1694, 'bug': 1695, 'bright': 1696, 'jimmi': 1697, 'capabl': 1698, 'fu': 1699, 'african': 1700, 'succeed': 1701, 'clark': 1702, 'stock': 1703, 'fat': 1704, 'presid': 1705, 'boat': 1706, 'spanish': 1707, 'gene': 1708, 'structur': 1709, 'kidnap': 1710, 'paper': 1711, 'whilst': 1712, 'belief': 1713, 'factor': 1714, 'attend': 1715, 'realis': 1716, 'educ': 1717, 'complic': 1718, 'tree': 1719, 'realism': 1720, 'bob': 1721, 'witti': 1722, 'assist': 1723, 'santa': 1724, 'finest': 1725, 'broken': 1726, 'up': 1727, 'v': 1728, 'observ': 1729, 'smoke': 1730, 'depart': 1731, 'determin': 1732, 'hat': 1733, 'lewi': 1734, 'fame': 1735, 'routin': 1736, 'oper': 1737, 'rubbish': 1738, 'domin': 1739, 'advanc': 1740, 'kinda': 1741, 'lone': 1742, 'foreign': 1743, 'safe': 1744, 'hook': 1745, 'morgan': 1746, 'rank': 1747, 'numer': 1748, 'vs': 1749, 'shallow': 1750, 'washington': 1751, 'werewolf': 1752, 'civil': 1753, 'shape': 1754, 'rose': 1755, 'gari': 1756, 'morn': 1757, 'winner': 1758, 'kong': 1759, 'ordinari': 1760, 'accomplish': 1761, 'peac': 1762, 'grab': 1763, 'whenev': 1764, 'virtual': 1765, 'h': 1766, 'luck': 1767, 'offens': 1768, 'patient': 1769, 'activ': 1770, 'complain': 1771, 'unfunni': 1772, 'bigger': 1773, 'welcom': 1774, 'contriv': 1775, 'pretend': 1776, 'dimension': 1777, 'trek': 1778, 'con': 1779, 'flash': 1780, 'eric': 1781, 'wake': 1782, 'code': 1783, 'dri': 1784, 'lesbian': 1785, 'cain': 1786, 'guard': 1787, 'albert': 1788, 'corrupt': 1789, 'manipul': 1790, 'statu': 1791, 'dancer': 1792, 'sourc': 1793, 'awkward': 1794, 'speech': 1795, 'gain': 1796, 'signific': 1797, 'context': 1798, 'anthoni': 1799, '13': 1800, 'corni': 1801, 'sean': 1802, 'psycho': 1803, 'clip': 1804, 'advic': 1805, 'reli': 1806, 'theatric': 1807, 'curiou': 1808, 'priest': 1809, 'w': 1810, 'religion': 1811, 'flow': 1812, 'addict': 1813, 'specif': 1814, 'secur': 1815, 'asian': 1816, 'jennif': 1817, 'skin': 1818, 'howard': 1819, 'organ': 1820, 'comfort': 1821, 'luke': 1822, 'core': 1823, 'golden': 1824, 'promot': 1825, 'lucki': 1826, 'cash': 1827, 'cheat': 1828, 'lower': 1829, 'associ': 1830, 'dislik': 1831, 'balanc': 1832, 'frequent': 1833, 'wing': 1834, 'frankli': 1835, 'contribut': 1836, 'degre': 1837, 'regret': 1838, 'spell': 1839, 'devic': 1840, 'forgiv': 1841, 'sake': 1842, 'print': 1843, 'lake': 1844, 'thoma': 1845, 'mass': 1846, 'betti': 1847, 'crack': 1848, 'unexpect': 1849, 'gordon': 1850, 'amateur': 1851, 'construct': 1852, 'grown': 1853, 'depend': 1854, 'unfold': 1855, 'categori': 1856, 'invit': 1857, 'intellectu': 1858, 'anna': 1859, 'grew': 1860, 'condit': 1861, 'walter': 1862, 'honor': 1863, 'matur': 1864, 'spectacular': 1865, 'sole': 1866, 'veteran': 1867, 'sudden': 1868, 'mirror': 1869, 'card': 1870, 'gift': 1871, 'robin': 1872, 'grip': 1873, 'freedom': 1874, 'meanwhil': 1875, 'demonstr': 1876, 'overli': 1877, 'liner': 1878, 'experienc': 1879, 'unabl': 1880, 'circumst': 1881, 'theori': 1882, 'brilliantli': 1883, 'subtitl': 1884, 'section': 1885, 'drew': 1886, 'crappi': 1887, 'colour': 1888, 'oliv': 1889, 'sheriff': 1890, 'sheer': 1891, 'cook': 1892, 'pile': 1893, 'path': 1894, 'parker': 1895, 'altern': 1896, 'matt': 1897, 'laughter': 1898, 'lawyer': 1899, 'accident': 1900, 'defin': 1901, 'relief': 1902, 'wander': 1903, 'treatment': 1904, 'hall': 1905, 'sinatra': 1906, 'captiv': 1907, 'hank': 1908, 'dragon': 1909, 'moor': 1910, 'halloween': 1911, 'gratuit': 1912, 'unintent': 1913, 'wound': 1914, 'k': 1915, 'barbara': 1916, 'wayn': 1917, 'cowboy': 1918, 'broadway': 1919, 'kung': 1920, 'jacki': 1921, 'statement': 1922, 'winter': 1923, 'surreal': 1924, 'spoof': 1925, 'canadian': 1926, 'fish': 1927, 'fare': 1928, 'cheer': 1929, 'treasur': 1930, 'gonna': 1931, 'compos': 1932, 'emerg': 1933, 'unrealist': 1934, 'victor': 1935, 'sensit': 1936, 'woodi': 1937, 'ran': 1938, 'driven': 1939, 'neighbor': 1940, 'sympathet': 1941, 'topic': 1942, 'expos': 1943, 'glass': 1944, 'authent': 1945, 'menac': 1946, 'overlook': 1947, 'ancient': 1948, 'gross': 1949, 'handsom': 1950, 'chief': 1951, 'michel': 1952, 'stranger': 1953, 'nevertheless': 1954, 'network': 1955, 'contemporari': 1956, 'russel': 1957, 'comedian': 1958, 'built': 1959, 'cinderella': 1960, 'feet': 1961, 'pleasant': 1962, 'letter': 1963, 'earn': 1964, 'endless': 1965, 'miser': 1966, 'consider': 1967, 'gori': 1968, 'underr': 1969, 'blockbust': 1970, 'solv': 1971, 'switch': 1972, 'brook': 1973, 'convict': 1974, 'bullet': 1975, 'edward': 1976, 'joseph': 1977, 'virgin': 1978, 'victoria': 1979, 'chosen': 1980, 'alex': 1981, '0': 1982, 'scenario': 1983, 'scale': 1984, 'cynic': 1985, 'com': 1986, 'outrag': 1987, 'curs': 1988, 'gut': 1989, 'sword': 1990, 'wrap': 1991, 'screenwrit': 1992, 'juli': 1993, 'proper': 1994, 'uk': 1995, 'monkey': 1996, 'substanc': 1997, 'driver': 1998, 'bird': 1999, 'remov': 2000, 'par': 2001, 'court': 2002, 'indic': 2003, 'naiv': 2004, 'grave': 2005, 'consequ': 2006, 'rental': 2007, 'nanci': 2008, 'roy': 2009, 'loser': 2010, 'inevit': 2011, 'advertis': 2012, 'germani': 2013, 'slap': 2014, 'invis': 2015, 'fatal': 2016, 'bridg': 2017, 'brave': 2018, 'le': 2019, 'footbal': 2020, 'anger': 2021, 'ador': 2022, 'provok': 2023, 'loui': 2024, 'alcohol': 2025, 'anderson': 2026, 'chan': 2027, 'stumbl': 2028, 'professor': 2029, 'willi': 2030, 'ryan': 2031, '1930': 2032, 'australian': 2033, 'assassin': 2034, 'bat': 2035, 'sharp': 2036, 'patrick': 2037, 'deni': 2038, 'heck': 2039, 'cell': 2040, 'eight': 2041, 'strongli': 2042, 'saturday': 2043, 'amateurish': 2044, 'ape': 2045, 'refresh': 2046, 'liber': 2047, 'trilog': 2048, 'lousi': 2049, 'sin': 2050, 'resid': 2051, 'justifi': 2052, 'vagu': 2053, 'san': 2054, 'defeat': 2055, 'reput': 2056, 'indi': 2057, 'terrifi': 2058, 'mini': 2059, 'creator': 2060, 'sympathi': 2061, 'endur': 2062, 'task': 2063, 'prevent': 2064, 'expert': 2065, 'tediou': 2066, 'tabl': 2067, 'offend': 2068, 'imit': 2069, 'employ': 2070, 'trial': 2071, 'basebal': 2072, 'rival': 2073, 'che': 2074, 'complaint': 2075, 'fairi': 2076, 'weekend': 2077, 'beach': 2078, 'europ': 2079, 'max': 2080, 'dig': 2081, 'pitch': 2082, 'risk': 2083, 'format': 2084, 'murphi': 2085, 'purchas': 2086, 'reminisc': 2087, 'bite': 2088, 'glimps': 2089, 'tini': 2090, 'harsh': 2091, 'nois': 2092, 'hype': 2093, 'powel': 2094, 'titan': 2095, 'asleep': 2096, '14': 2097, 'strip': 2098, 'north': 2099, 'till': 2100, 'fals': 2101, 'prime': 2102, 'destruct': 2103, 'revel': 2104, 'descript': 2105, 'africa': 2106, 'texa': 2107, 'uninterest': 2108, 'excess': 2109, 'semi': 2110, 'spin': 2111, 'sitcom': 2112, 'inner': 2113, 'surfac': 2114, 'arrest': 2115, 'massiv': 2116, 'argu': 2117, 'dinosaur': 2118, 'twin': 2119, 'maintain': 2120, 'makeup': 2121, 'hitchcock': 2122, 'controversi': 2123, 'insist': 2124, 'reject': 2125, 'ideal': 2126, 'ludicr': 2127, 'expens': 2128, 'melodrama': 2129, 'kim': 2130, 'stare': 2131, 'columbo': 2132, 'ala': 2133, 'forest': 2134, 'host': 2135, 'nail': 2136, 'atroci': 2137, 'supernatur': 2138, 'subplot': 2139, 'erot': 2140, 'press': 2141, 'ga': 2142, 'cant': 2143, 'dude': 2144, 'identifi': 2145, 'presum': 2146, 'notch': 2147, 'character': 2148, 'plagu': 2149, 'guest': 2150, 'crude': 2151, 'method': 2152, 'forgett': 2153, 'closer': 2154, 'landscap': 2155, 'beast': 2156, 'ear': 2157, 'princess': 2158, 'foster': 2159, 'border': 2160, 'lion': 2161, 'birth': 2162, 'previous': 2163, 'pacino': 2164, 'jungl': 2165, 'aunt': 2166, 'storytel': 2167, 'damag': 2168, 'accus': 2169, 'bound': 2170, 'urban': 2171, 'thirti': 2172, 'doll': 2173, 'chose': 2174, 'guid': 2175, 'nude': 2176, 'emma': 2177, 'propaganda': 2178, 'jess': 2179, 'warrior': 2180, 'whoever': 2181, 'mate': 2182, 'mainstream': 2183, 'pet': 2184, '25': 2185, 'upset': 2186, 'latest': 2187, 'exact': 2188, 'cooper': 2189, 'size': 2190, 'poster': 2191, 'deadli': 2192, 'merit': 2193, 'friday': 2194, 'gritti': 2195, 'sun': 2196, 'corps': 2197, 'ton': 2198, '1990': 2199, 'citizen': 2200, 'rough': 2201, 'wilson': 2202, 'settl': 2203, 'contest': 2204, 'warner': 2205, 'buff': 2206, 'popul': 2207, 'contact': 2208, 'blend': 2209, 'pitt': 2210, 'mgm': 2211, 'overcom': 2212, 'rat': 2213, 'widow': 2214, 'bu': 2215, 'alic': 2216, 'select': 2217, 'environ': 2218, 'metal': 2219, 'guilti': 2220, 'lift': 2221, 'revolut': 2222, 'particip': 2223, 'link': 2224, 'ted': 2225, 'corpor': 2226, 'afternoon': 2227, 'accompani': 2228, 'johnson': 2229, 'prostitut': 2230, 'moron': 2231, 'exagger': 2232, 'corner': 2233, '1960': 2234, 'matrix': 2235, 'friendli': 2236, 'hood': 2237, 'multipl': 2238, 'sincer': 2239, 'instal': 2240, 'leagu': 2241, 'doom': 2242, 'clair': 2243, 'holm': 2244, 'aka': 2245, 'advis': 2246, 'sunday': 2247, 'junk': 2248, 'campi': 2249, 'defend': 2250, 'examin': 2251, 'hip': 2252, 'string': 2253, 'irish': 2254, 'grim': 2255, 'blah': 2256, 'lugosi': 2257, 'shut': 2258, 'pro': 2259, 'varieti': 2260, 'confid': 2261, 'tight': 2262, 'rachel': 2263, 'icon': 2264, 'shake': 2265, 'directli': 2266, 'mexican': 2267, 'jaw': 2268, 'attach': 2269, 'denni': 2270, 'goal': 2271, 'sullivan': 2272, 'medic': 2273, 'breast': 2274, 'legendari': 2275, 'vietnam': 2276, 'prior': 2277, 'truck': 2278, 'bourn': 2279, 'sentenc': 2280, 'courag': 2281, 'duke': 2282, 'terrorist': 2283, 'sarah': 2284, 'dean': 2285, 'proceed': 2286, 'yell': 2287, 'donald': 2288, 'entri': 2289, 'hong': 2290, 'un': 2291, 'split': 2292, 'nose': 2293, 'behav': 2294, 'jerk': 2295, 'unconvinc': 2296, 'confess': 2297, 'stolen': 2298, 'forth': 2299, 'borrow': 2300, 'concentr': 2301, 'swim': 2302, 'crush': 2303, 'everywher': 2304, 'buri': 2305, 'lifetim': 2306, 'gather': 2307, 'julia': 2308, 'spite': 2309, 'turkey': 2310, 'california': 2311, 'pan': 2312, 'lip': 2313, 'deliveri': 2314, 'hoffman': 2315, 'reward': 2316, 'offici': 2317, 'quest': 2318, 'china': 2319, 'proud': 2320, 'flight': 2321, 'downright': 2322, 'freeman': 2323, 'sir': 2324, 'fade': 2325, 'lazi': 2326, 'encourag': 2327, 'notori': 2328, 'sink': 2329, 'jon': 2330, 'betray': 2331, 'worthwhil': 2332, 'fabul': 2333, 'jail': 2334, 'inept': 2335, 'relev': 2336, 'imageri': 2337, 'cousin': 2338, 'bell': 2339, 'shower': 2340, 'bag': 2341, 'susan': 2342, 'teeth': 2343, 'survivor': 2344, 'lisa': 2345, 'retard': 2346, 'storm': 2347, 'branagh': 2348, 'trade': 2349, 'bride': 2350, 'quirki': 2351, 'tremend': 2352, 'facial': 2353, 'mexico': 2354, 'stab': 2355, 'shark': 2356, 'alright': 2357, 'hugh': 2358, 'finger': 2359, 'toler': 2360, 'summari': 2361, 'bitter': 2362, 'ha': 2363, 'blown': 2364, 'hyster': 2365, 'pose': 2366, 'von': 2367, 'ned': 2368, 'scheme': 2369, 'ron': 2370, 'address': 2371, 'bone': 2372, 'larri': 2373, 'cruel': 2374, 'afterward': 2375, 'christ': 2376, 'feed': 2377, 'swear': 2378, 'thumb': 2379, 'pursu': 2380, 'distinct': 2381, 'screw': 2382, 'snake': 2383, 'beg': 2384, 'traci': 2385, 'tour': 2386, 'stomach': 2387, 'occas': 2388, 'mechan': 2389, 'photo': 2390, 'obscur': 2391, 'raw': 2392, 'chair': 2393, 'resist': 2394, 'chain': 2395, 'southern': 2396, 'render': 2397, 'heavili': 2398, 'argument': 2399, 'necessarili': 2400, 'gruesom': 2401, 'holiday': 2402, 'cabin': 2403, 'hardi': 2404, 'sidney': 2405, 'india': 2406, 'racist': 2407, 'indulg': 2408, 'philip': 2409, 'satan': 2410, 'understood': 2411, 'tongu': 2412, 'belov': 2413, 'stalk': 2414, 'midnight': 2415, 'outfit': 2416, 'integr': 2417, 'obnoxi': 2418, 'fourth': 2419, 'lay': 2420, 'forgot': 2421, 'pregnant': 2422, 'carol': 2423, 'ticket': 2424, 'inhabit': 2425, '17': 2426, 'garden': 2427, 'restor': 2428, 'magazin': 2429, 'deeper': 2430, 'slapstick': 2431, 'brad': 2432, 'incid': 2433, 'shoe': 2434, 'devot': 2435, 'lincoln': 2436, 'divorc': 2437, 'disbelief': 2438, 'elizabeth': 2439, 'lili': 2440, 'anticip': 2441, 'underground': 2442, 'guarante': 2443, 'benefit': 2444, 'sandler': 2445, 'maria': 2446, 'amazingli': 2447, 'mildli': 2448, 'capit': 2449, 'greater': 2450, 'cring': 2451, 'creation': 2452, 'slave': 2453, 'explod': 2454, 'princip': 2455, 'bbc': 2456, 'halfway': 2457, 'funnier': 2458, 'introduct': 2459, 'extraordinari': 2460, 'lesli': 2461, 'advantag': 2462, 'enhanc': 2463, 'extent': 2464, 'transfer': 2465, 'punish': 2466, 'overwhelm': 2467, 'wreck': 2468, 'text': 2469, 'tap': 2470, 'dynam': 2471, 'lane': 2472, 'preview': 2473, 'error': 2474, 'east': 2475, 'plant': 2476, 'deliber': 2477, 'horrif': 2478, 'jessica': 2479, 'lo': 2480, 'miscast': 2481, 'homosexu': 2482, 'vincent': 2483, 'miller': 2484, 'sophist': 2485, 'vacat': 2486, 'basi': 2487, 'ensu': 2488, '2000': 2489, 'appli': 2490, 'steel': 2491, 'measur': 2492, 'sleazi': 2493, 'uncomfort': 2494, 'via': 2495, 'reed': 2496, 'bollywood': 2497, 'elev': 2498, 'extend': 2499, 'mansion': 2500, 'spoken': 2501, 'dentist': 2502, 'blair': 2503, 'daili': 2504, 'breathtak': 2505, 'overact': 2506, 'beer': 2507, 'goofi': 2508, 'melt': 2509, 'assign': 2510, 'savag': 2511, 'stanley': 2512, 'fix': 2513, 'alter': 2514, 'cathol': 2515, 'hippi': 2516, 'conceiv': 2517, 'mous': 2518, 'oppos': 2519, 'nowaday': 2520, 'sacrific': 2521, 'subsequ': 2522, 'burt': 2523, 'everyday': 2524, 'properli': 2525, 'succe': 2526, 'carpent': 2527, 'inspector': 2528, 'laura': 2529, 'circl': 2530, 'neck': 2531, 'block': 2532, 'massacr': 2533, 'grey': 2534, 'christi': 2535, 'portrait': 2536, 'lesser': 2537, 'mob': 2538, 'fallen': 2539, 'access': 2540, 'pool': 2541, 'fay': 2542, 'concert': 2543, 'seagal': 2544, 'chees': 2545, 'react': 2546, 'sinist': 2547, 'relax': 2548, 'isol': 2549, 'competit': 2550, 'jewish': 2551, 'usa': 2552, 'jake': 2553, 'appal': 2554, '2006': 2555, 'nonetheless': 2556, 'immens': 2557, 'stink': 2558, 'creep': 2559, 'nine': 2560, 'chop': 2561, 'lyric': 2562, 'suitabl': 2563, 'spiritu': 2564, 'ironi': 2565, 'user': 2566, 'showcas': 2567, 'rage': 2568, 'shirt': 2569, 'spring': 2570, 'needless': 2571, 'retir': 2572, 'franchis': 2573, 'reduc': 2574, 'luci': 2575, 'nut': 2576, 'adopt': 2577, 'navi': 2578, 'sold': 2579, 'nurs': 2580, 'per': 2581, 'bath': 2582, 'digit': 2583, 'uninspir': 2584, 'zone': 2585, 'bulli': 2586, 'asham': 2587, 'jay': 2588, 'stanwyck': 2589, 'amongst': 2590, 'illustr': 2591, 'laid': 2592, 'upper': 2593, 'sutherland': 2594, '2001': 2595, 'oddli': 2596, 'broadcast': 2597, '1940': 2598, 'fulfil': 2599, 'disguis': 2600, 'brando': 2601, 'aspir': 2602, 'stylish': 2603, 'throat': 2604, 'baker': 2605, 'endear': 2606, 'pound': 2607, 'nobl': 2608, 'wanna': 2609, '18': 2610, 'em': 2611, 'thief': 2612, 'impli': 2613, 'wwii': 2614, 'neighborhood': 2615, 'pride': 2616, 'shoulder': 2617, 'cinematograph': 2618, 'albeit': 2619, 'shift': 2620, 'dinner': 2621, 'distribut': 2622, '16': 2623, 'prop': 2624, 'diseas': 2625, 'bett': 2626, 'tens': 2627, 'dawn': 2628, 'bo': 2629, 'coher': 2630, 'rochest': 2631, 'poignant': 2632, 'knife': 2633, 'snow': 2634, 'wash': 2635, 'shout': 2636, 'contract': 2637, 'forti': 2638, 'function': 2639, 'silenc': 2640, 'surf': 2641, 'rebel': 2642, 'matthau': 2643, 'proof': 2644, 'height': 2645, 'derek': 2646, 'chuck': 2647, 'heat': 2648, 'cannib': 2649, 'henc': 2650, 'duti': 2651, 'reunion': 2652, 'horrend': 2653, 'instinct': 2654, 'mindless': 2655, 'eeri': 2656, 'internet': 2657, 'elvira': 2658, 'cancel': 2659, 'silver': 2660, 'widmark': 2661, 'pie': 2662, 'repetit': 2663, 'innov': 2664, 'incoher': 2665, 'alik': 2666, 'torn': 2667, 'neat': 2668, 'elvi': 2669, 'musician': 2670, 'greatli': 2671, 'premier': 2672, 'absorb': 2673, 'spielberg': 2674, 'mill': 2675, 'glori': 2676, 'etern': 2677, 'diamond': 2678, 'lovabl': 2679, 'britain': 2680, 'burton': 2681, 'trite': 2682, 'redempt': 2683, 'wealthi': 2684, 'horrifi': 2685, 'infam': 2686, 'nelson': 2687, 'itali': 2688, 'announc': 2689, 'blank': 2690, 'homag': 2691, 'crisi': 2692, 'bang': 2693, 'precis': 2694, 'racism': 2695, 'fbi': 2696, 'flop': 2697, 'hammer': 2698, 'resolut': 2699, 'parallel': 2700, 'dedic': 2701, 'helen': 2702, 'pat': 2703, 'chaplin': 2704, 'wilder': 2705, 'streisand': 2706, 'happili': 2707, 'ensembl': 2708, 'conclud': 2709, 'broke': 2710, 'triumph': 2711, 'cube': 2712, 'carter': 2713, 'factori': 2714, 'disagre': 2715, 'plastic': 2716, 'st': 2717, 'oil': 2718, 'mar': 2719, 'row': 2720, 'rocket': 2721, 'march': 2722, 'chuckl': 2723, 'climb': 2724, 'weight': 2725, 'bush': 2726, 'own': 2727, 'fighter': 2728, 'vega': 2729, 'dump': 2730, 'meaning': 2731, 'sensibl': 2732, 'boot': 2733, 'enorm': 2734, 'kurt': 2735, 'luca': 2736, 'thug': 2737, 'unforgett': 2738, 'spare': 2739, 'mst3k': 2740, 'lust': 2741, 'wherea': 2742, 'dane': 2743, 'bobbi': 2744, 'fifti': 2745, 'difficulti': 2746, 'butt': 2747, 'adequ': 2748, 'threat': 2749, 'dear': 2750, 'engin': 2751, 'stress': 2752, 'arnold': 2753, 'karloff': 2754, 'caricatur': 2755, 'rap': 2756, 'brand': 2757, 'hamlet': 2758, 'fest': 2759, 'ralph': 2760, 'arrog': 2761, 'swing': 2762, 'homeless': 2763, 'elabor': 2764, 'barri': 2765, 'ego': 2766, 'flynn': 2767, 'secretari': 2768, 'journalist': 2769, 'polish': 2770, 'simpson': 2771, 'arrang': 2772, 'conspiraci': 2773, 'fanci': 2774, 'float': 2775, 'grate': 2776, 'puppet': 2777, 'spike': 2778, 'induc': 2779, 'resort': 2780, 'unbear': 2781, 'tool': 2782, 'cruis': 2783, 'choreograph': 2784, 'phillip': 2785, 'pig': 2786, 'tribut': 2787, 'guilt': 2788, 'basement': 2789, 'exercis': 2790, 'muppet': 2791, 'boll': 2792, 'file': 2793, 'fianc': 2794, 'ham': 2795, 'medium': 2796, 'scarecrow': 2797, 'editor': 2798, 'slip': 2799, 'layer': 2800, 'document': 2801, 'babe': 2802, 'toilet': 2803, 'tower': 2804, '24': 2805, 'item': 2806, 'stan': 2807, 'puzzl': 2808, 'korean': 2809, 'ward': 2810, 'larger': 2811, 'assur': 2812, 'denzel': 2813, 'persona': 2814, 'territori': 2815, 'orient': 2816, 'spark': 2817, 'philosoph': 2818, 'inexplic': 2819, 'catherin': 2820, 'doc': 2821, 'minim': 2822, 'transit': 2823, 'portion': 2824, 'slaughter': 2825, 'glover': 2826, 'superfici': 2827, 'librari': 2828, 'walken': 2829, 'sneak': 2830, 'financi': 2831, 'ban': 2832, 'shi': 2833, 'owe': 2834, 'wolf': 2835, 'dorothi': 2836, 'jeremi': 2837, 'pg': 2838, 'jet': 2839, 'boredom': 2840, 'curti': 2841, 'hudson': 2842, 'profound': 2843, 'metaphor': 2844, 'backdrop': 2845, 'ambigu': 2846, 'whale': 2847, 'eleph': 2848, 'multi': 2849, 'cusack': 2850, 'stiff': 2851, 'union': 2852, 'implaus': 2853, '2005': 2854, 'birthday': 2855, 'ultra': 2856, 'rave': 2857, 'gadget': 2858, 'notion': 2859, 'elsewher': 2860, 'viru': 2861, 'hack': 2862, '1st': 2863, 'disc': 2864, 'afford': 2865, 'superhero': 2866, 'reader': 2867, 'slight': 2868, 'hawk': 2869, 'lloyd': 2870, 'eva': 2871, 'bibl': 2872, 'distanc': 2873, 'squar': 2874, 'poison': 2875, 'deriv': 2876, 'newspap': 2877, 'urg': 2878, 'pad': 2879, 'eastwood': 2880, 'canada': 2881, 'health': 2882, 'essenc': 2883, 'charisma': 2884, 'drown': 2885, 'heston': 2886, 'spread': 2887, 'montag': 2888, 'restaur': 2889, 'skit': 2890, 'cure': 2891, 'button': 2892, 'sadist': 2893, 'huh': 2894, 'companion': 2895, 'lab': 2896, 'gradual': 2897, 'godfath': 2898, 'invest': 2899, 'fetch': 2900, 'dealt': 2901, 'muslim': 2902, 'maniac': 2903, 'scoobi': 2904, 'peak': 2905, 'estat': 2906, 'countless': 2907, 'tea': 2908, 'cup': 2909, 'subtleti': 2910, 'kane': 2911, 'servant': 2912, 'ritter': 2913, 'miik': 2914, 'gothic': 2915, 'alli': 2916, 'salli': 2917, 'briefli': 2918, 'charismat': 2919, 'iii': 2920, 'elect': 2921, 'electr': 2922, 'heroic': 2923, 'wannab': 2924, 'resourc': 2925, 'grandmoth': 2926, 'admittedli': 2927, 'tender': 2928, 'ingredi': 2929, 'neil': 2930, 'nuanc': 2931, 'toss': 2932, 'cole': 2933, 'bud': 2934, 'reel': 2935, 'mild': 2936, 'kubrick': 2937, 'shall': 2938, 'stood': 2939, 'punk': 2940, 'mafia': 2941, 'stronger': 2942, 'gate': 2943, 'label': 2944, 'dawson': 2945, 'pit': 2946, 'poverti': 2947, 'pauli': 2948, 'carrey': 2949, 'reev': 2950, 'fond': 2951, 'outcom': 2952, 'cox': 2953, 'burst': 2954, 'terri': 2955, 'ian': 2956, 'assault': 2957, 'tag': 2958, 'useless': 2959, 'smooth': 2960, 'easier': 2961, 'astair': 2962, 'updat': 2963, 'smash': 2964, 'cardboard': 2965, 'bakshi': 2966, 'fist': 2967, 'coincid': 2968, 'rex': 2969, 'exchang': 2970, 'melodramat': 2971, 'vulner': 2972, 'samurai': 2973, 'qualifi': 2974, 'resolv': 2975, '2002': 2976, 'divers': 2977, 'sketch': 2978, 'increasingli': 2979, 'vari': 2980, 'be': 2981, 'tame': 2982, 'blast': 2983, 'insert': 2984, 'conveni': 2985, 'reynold': 2986, 'templ': 2987, 'scratch': 2988, 'luckili': 2989, 'suspend': 2990, 'brillianc': 2991, 'fisher': 2992, 'soprano': 2993, 'seventi': 2994, 'gotta': 2995, 'hamilton': 2996, 'meat': 2997, 'strictli': 2998, 'farm': 2999, 'ambiti': 3000, 'coach': 3001, 'nuclear': 3002, 'pin': 3003, 'jami': 3004, 'walker': 3005, 'matthew': 3006, 'struck': 3007, 'worthless': 3008, 'ninja': 3009, 'instantli': 3010, 'butcher': 3011, 'grasp': 3012, 'kudo': 3013, 'recreat': 3014, 'empir': 3015, 'convolut': 3016, 'monk': 3017, 'discoveri': 3018, 'timeless': 3019, 'closet': 3020, 'revers': 3021, 'clock': 3022, 'brosnan': 3023, 'spooki': 3024, 'cave': 3025, 'eccentr': 3026, 'joey': 3027, 'wipe': 3028, 'cliff': 3029, 'declar': 3030, 'communist': 3031, 'inconsist': 3032, 'clown': 3033, 'sloppi': 3034, 'sidekick': 3035, 'importantli': 3036, 'pal': 3037, 'gray': 3038, 'miracl': 3039, 'evok': 3040, 'bleak': 3041, 'norman': 3042, 'eighti': 3043, 'seller': 3044, 'partli': 3045, 'selfish': 3046, 'fifteen': 3047, 'mitchel': 3048, 'ho': 3049, 'cheek': 3050, '45': 3051, 'flawless': 3052, 'destin': 3053, 'chew': 3054, 'superbl': 3055, 'farc': 3056, 'stoog': 3057, 'seed': 3058, 'lifestyl': 3059, 'piano': 3060, 'websit': 3061, 'psychiatrist': 3062, 'debat': 3063, 'enthusiast': 3064, 'australia': 3065, 'aforement': 3066, 'directori': 3067, 'incompet': 3068, 'soviet': 3069, 'wick': 3070, 'splatter': 3071, 'abc': 3072, 'kitchen': 3073, 'dire': 3074, 'wrestl': 3075, 'dash': 3076, 'emili': 3077, 'drivel': 3078, 'pressur': 3079, 'bash': 3080, 'regardless': 3081, 'slice': 3082, 'akshay': 3083, 'anni': 3084, 'beaten': 3085, 'seduc': 3086, 'helicopt': 3087, 'curios': 3088, 'lou': 3089, 'boil': 3090, 'recov': 3091, 'cameron': 3092, 'flower': 3093, 'duo': 3094, 'prize': 3095, 'increas': 3096, 'glow': 3097, 'suppli': 3098, 'chapter': 3099, 'cagney': 3100, 'judi': 3101, 'jar': 3102, 'pleasantli': 3103, 'ken': 3104, 'cia': 3105, 'artifici': 3106, 'doo': 3107, 'distant': 3108, 'dave': 3109, 'blob': 3110, 'mann': 3111, 'combat': 3112, 'goldberg': 3113, 'turner': 3114, 'glenn': 3115, 'craig': 3116, 'ellen': 3117, 'hop': 3118, 'panic': 3119, 'web': 3120, 'ranger': 3121, 'eleg': 3122, 'perri': 3123, 'favour': 3124, 'psychot': 3125, 'craven': 3126, 'splendid': 3127, 'francisco': 3128, 'drunken': 3129, 'laurel': 3130, 'graduat': 3131, 'flip': 3132, 'slightest': 3133, 'gentl': 3134, 'plausibl': 3135, 'modesti': 3136, 'falk': 3137, 'rid': 3138, 'philosophi': 3139, '20th': 3140, 'shortli': 3141, 'hatr': 3142, 'ruth': 3143, 'greek': 3144, 'alexand': 3145, 'min': 3146, 'fx': 3147, 'gandhi': 3148, 'wizard': 3149, 'holi': 3150, 'unpleas': 3151, 'jealou': 3152, 'tall': 3153, 'dracula': 3154, 'futurist': 3155, 'felix': 3156, 'harm': 3157, 'ocean': 3158, 'manhattan': 3159, 'legal': 3160, 'we': 3161, 'preciou': 3162, 'lend': 3163, 'knight': 3164, 'fund': 3165, 'reviv': 3166, 'explicit': 3167, 'mock': 3168, 'forbidden': 3169, 'nod': 3170, 'scientif': 3171, 'giallo': 3172, 'childish': 3173, 'digniti': 3174, 'ami': 3175, 'bless': 3176, 'tank': 3177, 'overdon': 3178, 'thread': 3179, 'torment': 3180, 'pirat': 3181, 'awe': 3182, '2004': 3183, 'broad': 3184, 'repeatedli': 3185, 'mel': 3186, 'yesterday': 3187, 'unwatch': 3188, 'margaret': 3189, 'eve': 3190, 'awaken': 3191, 'verhoeven': 3192, '99': 3193, 'elderli': 3194, 'nerv': 3195, 'thick': 3196, 'fever': 3197, 'timothi': 3198, 'ah': 3199, 'bin': 3200, 'eas': 3201, 'uniform': 3202, 'acclaim': 3203, 'absenc': 3204, 'stiller': 3205, 'lean': 3206, 'royal': 3207, 'kay': 3208, 'ambit': 3209, 'publish': 3210, 'launch': 3211, 'roman': 3212, 'rivet': 3213, 'romero': 3214, 'custom': 3215, 'automat': 3216, 'politician': 3217, 'griffith': 3218, 'pulp': 3219, 'darker': 3220, 'antic': 3221, 'purpl': 3222, 'phrase': 3223, 'wallac': 3224, 'foul': 3225, 'homicid': 3226, 'transport': 3227, 'stinker': 3228, 'warren': 3229, 'gabriel': 3230, 'pierc': 3231, 'bathroom': 3232, 'crook': 3233, 'termin': 3234, 'sunshin': 3235, 'tomato': 3236, '2003': 3237, 'pray': 3238, 'rambo': 3239, 'sixti': 3240, 'q': 3241, 'brazil': 3242, 'album': 3243, 'awak': 3244, 'coloni': 3245, 'horrid': 3246, 'viciou': 3247, 'donna': 3248, 'contrari': 3249, 'packag': 3250, 'choreographi': 3251, 'karen': 3252, 'revolutionari': 3253, 'evolv': 3254, 'prom': 3255, 'saint': 3256, 'hollow': 3257, 'juvenil': 3258, 'kenneth': 3259, 'marin': 3260, 'li': 3261, 'ought': 3262, 'eyr': 3263, 'ireland': 3264, 'overr': 3265, 'kapoor': 3266, 'boast': 3267, 'blade': 3268, 'dose': 3269, 'stole': 3270, 'twelv': 3271, 'conserv': 3272, 'defi': 3273, 'candid': 3274, 'option': 3275, 'mildr': 3276, 'nerd': 3277, 'beatti': 3278, 'ramon': 3279, 'mummi': 3280, 'altman': 3281, 'collabor': 3282, 'trio': 3283, 'astonish': 3284, 'detract': 3285, 'global': 3286, 'protest': 3287, 'flame': 3288, 'confirm': 3289, 'fulci': 3290, 'funer': 3291, 'jazz': 3292, 'kirk': 3293, 'natali': 3294, 'whip': 3295, 'bull': 3296, 'shade': 3297, 'enterpris': 3298, 'tommi': 3299, 'audio': 3300, 'bottl': 3301, 'delici': 3302, 'yellow': 3303, 'spit': 3304, 'leap': 3305, 'blake': 3306, 'nicholson': 3307, 'mystic': 3308, 'destini': 3309, 'racial': 3310, 'reunit': 3311, 'threw': 3312, 'vivid': 3313, 'swedish': 3314, 'pseudo': 3315, 'merci': 3316, 'meaningless': 3317, 'visibl': 3318, 'inherit': 3319, 'adolesc': 3320, 'bedroom': 3321, 'harder': 3322, 'altogeth': 3323, 'neo': 3324, 'staff': 3325, 'todd': 3326, 'popcorn': 3327, 'fonda': 3328, 'enchant': 3329, 'befriend': 3330, 'edi': 3331, 'exhibit': 3332, 'reserv': 3333, 'await': 3334, 'suspici': 3335, 'tip': 3336, 'synopsi': 3337, 'uneven': 3338, 'ruthless': 3339, 'respond': 3340, 'moodi': 3341, 'decor': 3342, 'voight': 3343, 'bust': 3344, 'fanat': 3345, 'roommat': 3346, 'wire': 3347, 'jew': 3348, 'lawrenc': 3349, 'lemmon': 3350, 'crocodil': 3351, 'madonna': 3352, 'leonard': 3353, 'kennedi': 3354, 'atlanti': 3355, 'garner': 3356, 'audit': 3357, 'incident': 3358, '2007': 3359, 'unsettl': 3360, 'bargain': 3361, 'bradi': 3362, 'holli': 3363, 'abysm': 3364, 'palma': 3365, 'centr': 3366, 'bold': 3367, 'clumsi': 3368, 'voyag': 3369, 'chao': 3370, 'carl': 3371, 'ventur': 3372, 'clint': 3373, 'rural': 3374, 'dimens': 3375, 'trail': 3376, 'elimin': 3377, 'cuba': 3378, 'acknowledg': 3379, 'troop': 3380, 'humili': 3381, '2nd': 3382, 'daddi': 3383, 'echo': 3384, 'lit': 3385, 'cari': 3386, 'nearbi': 3387, 'characterist': 3388, 'neglect': 3389, 'ant': 3390, 'mall': 3391, 'poetic': 3392, 'wealth': 3393, 'cd': 3394, 'immigr': 3395, 'timon': 3396, 'imperson': 3397, 'tiger': 3398, 'hart': 3399, 'versu': 3400, 'domest': 3401, 'paus': 3402, 'prejudic': 3403, 'jeffrey': 3404, 'marshal': 3405, 'celluloid': 3406, 'saga': 3407, 'mistaken': 3408, 'collaps': 3409, 'solo': 3410, 'repuls': 3411, 'pun': 3412, 'homer': 3413, 'infect': 3414, 'mickey': 3415, 'inan': 3416, 'pant': 3417, 'sore': 3418, 'chest': 3419, 'apolog': 3420, 'leon': 3421, 'olivi': 3422, 'hbo': 3423, 'gear': 3424, 'tribe': 3425, 'coat': 3426, 'assembl': 3427, 'inappropri': 3428, 'interrupt': 3429, 'undoubtedli': 3430, 'equip': 3431, 'cake': 3432, 'ginger': 3433, 'harvey': 3434, 'milk': 3435, 'coffe': 3436, 'promin': 3437, '1996': 3438, 'institut': 3439, 'trace': 3440, 'highest': 3441, 'colonel': 3442, 'furthermor': 3443, 'florida': 3444, 'jenni': 3445, 'pen': 3446, 'retain': 3447, 'maggi': 3448, 'exot': 3449, 'humbl': 3450, 'devast': 3451, 'instant': 3452, 'airplan': 3453, 'pot': 3454, 'embrac': 3455, 'consum': 3456, 'primari': 3457, 'vulgar': 3458, 'solut': 3459, 'colleagu': 3460, 'aveng': 3461, 'brooklyn': 3462, 'polanski': 3463, 'strain': 3464, '1999': 3465, 'principl': 3466, 'poke': 3467, 'illog': 3468, '3rd': 3469, 'descend': 3470, 'outer': 3471, 'sale': 3472, 'wive': 3473, 'bowl': 3474, 'cope': 3475, 'ya': 3476, 'dian': 3477, 'gender': 3478, 'godzilla': 3479, 'linda': 3480, 'dutch': 3481, 'smaller': 3482, 'disabl': 3483, 'seduct': 3484, 'rick': 3485, 'blatant': 3486, 'cue': 3487, 'hal': 3488, 'mixtur': 3489, 'inferior': 3490, 'glamor': 3491, 'scope': 3492, 'predecessor': 3493, 'gloriou': 3494, 'devoid': 3495, 'rabbit': 3496, 'dud': 3497, 'primarili': 3498, 'dive': 3499, 'secondli': 3500, 'lol': 3501, 'vast': 3502, 'yard': 3503, 'gundam': 3504, 'bubbl': 3505, 'beneath': 3506, 'breed': 3507, 'talki': 3508, 'garbo': 3509, 'trademark': 3510, 'casual': 3511, 'countrysid': 3512, 'disjoint': 3513, 'domino': 3514, 'aggress': 3515, 'senseless': 3516, 'alert': 3517, 'alfr': 3518, 'museum': 3519, 'shirley': 3520, 'hideou': 3521, 'z': 3522, 'grinch': 3523, 'shelf': 3524, 'et': 3525, 'arab': 3526, 'streep': 3527, 'pearl': 3528, 'simplist': 3529, 'myer': 3530, 'april': 3531, 'invas': 3532, 'khan': 3533, 'stir': 3534, 'loyal': 3535, 'robberi': 3536, 'stellar': 3537, 'obtain': 3538, 'vanish': 3539, 'maci': 3540, 'mail': 3541, 'hardcor': 3542, 'stack': 3543, 'defens': 3544, 'experiment': 3545, 'acid': 3546, 'boom': 3547, 'unhappi': 3548, 'robinson': 3549, 'sh': 3550, 'slide': 3551, 'mayor': 3552, 'illeg': 3553, 'disgrac': 3554, 'applaud': 3555, 'rendit': 3556, 'uwe': 3557, 'oz': 3558, 'hopeless': 3559, 'dismiss': 3560, 'span': 3561, 'spider': 3562, 'topless': 3563, 'wont': 3564, 'incomprehens': 3565, 'blew': 3566, 'tempt': 3567, 'psychic': 3568, 'amanda': 3569, 'grandfath': 3570, 'berlin': 3571, 'counter': 3572, 'emphasi': 3573, 'recruit': 3574, 'scroog': 3575, 'dicken': 3576, 'declin': 3577, 'fri': 3578, 'soccer': 3579, 'craze': 3580, 'tenant': 3581, 'diana': 3582, 'rifl': 3583, 'hartley': 3584, 'wet': 3585, 'goer': 3586, 'parad': 3587, 'faster': 3588, 'ration': 3589, 'riot': 3590, 'woo': 3591, 'intim': 3592, 'niro': 3593, 'ethnic': 3594, 'sympath': 3595, 'shed': 3596, 'resurrect': 3597, 'revolt': 3598, 'trashi': 3599, 'bitch': 3600, 'sibl': 3601, 'lumet': 3602, 'shaw': 3603, 'porno': 3604, 'justin': 3605, 'honesti': 3606, 'eager': 3607, 'commend': 3608, 'farmer': 3609, 'nephew': 3610, 'rider': 3611, 'steam': 3612, 'gap': 3613, 'mario': 3614, 'partial': 3615, 'wheel': 3616, 'andr': 3617, 'hopper': 3618, 'ballet': 3619, '00': 3620, 'jonathan': 3621, 'choru': 3622, 'wendi': 3623, 'unreal': 3624, 'feminist': 3625, 'hesit': 3626, 'immort': 3627, 'patriot': 3628, 'dealer': 3629, 'ensur': 3630, 'region': 3631, 'slick': 3632, 'enlighten': 3633, 'biographi': 3634, 'lena': 3635, 'weakest': 3636, 'worm': 3637, 'victori': 3638, 'prequel': 3639, 'owen': 3640, 'properti': 3641, 'sappi': 3642, 'snap': 3643, 'vice': 3644, 'franco': 3645, 'nostalg': 3646, 'charlott': 3647, 'util': 3648, 'hung': 3649, 'repress': 3650, 'morri': 3651, 'kingdom': 3652, 'wore': 3653, 'confin': 3654, 'skull': 3655, 'psychopath': 3656, 'similarli': 3657, 'leo': 3658, 'mutant': 3659, 'blunt': 3660, 'safeti': 3661, 'composit': 3662, 'sandra': 3663, 'macarthur': 3664, 'campbel': 3665, 'compens': 3666, 'recycl': 3667, 'heartbreak': 3668, 'whoopi': 3669, 'despair': 3670, 'compass': 3671, 'del': 3672, 'montana': 3673, 'drain': 3674, 'pattern': 3675, 'speci': 3676, 'thru': 3677, 'cg': 3678, 'nervou': 3679, 'latin': 3680, 'tad': 3681, 'rambl': 3682, 'tail': 3683, 'dust': 3684, 'bumbl': 3685, 'rope': 3686, 'bonu': 3687, 'snl': 3688, 'bergman': 3689, 'valuabl': 3690, 'repli': 3691, 'acquir': 3692, 'kyle': 3693, 'bow': 3694, 'exit': 3695, '1972': 3696, 'drum': 3697, 'deed': 3698, 'miseri': 3699, 'strand': 3700, 'farrel': 3701, 'emperor': 3702, 'rocki': 3703, 'dalton': 3704, 'hyde': 3705, 'romp': 3706, 'rotten': 3707, '35': 3708, 'gal': 3709, 'tonight': 3710, 'wacki': 3711, 'carradin': 3712, 'downhil': 3713, 'contempl': 3714, 'pour': 3715, 'oppress': 3716, 'martian': 3717, 'roth': 3718, 'radic': 3719, 'da': 3720, 'mistress': 3721, 'gimmick': 3722, 'slug': 3723, 'bleed': 3724, 'orson': 3725, 'chess': 3726, 'percept': 3727, 'olli': 3728, 'airport': 3729, 'rapist': 3730, 'slash': 3731, 'stilt': 3732, 'arc': 3733, 'dazzl': 3734, 'tackl': 3735, 'unpredict': 3736, 'programm': 3737, 'paltrow': 3738, 'belt': 3739, 'pursuit': 3740, 'pervers': 3741, 'attorney': 3742, 'melodi': 3743, 'tooth': 3744, 'shelley': 3745, 'heal': 3746, 'taught': 3747, 'edgar': 3748, 'preach': 3749, 'arguabl': 3750, 'pervert': 3751, 'mislead': 3752, '1983': 3753, 'champion': 3754, 'banal': 3755, 'plight': 3756, 'vengeanc': 3757, 'closest': 3758, 'uplift': 3759, 'virginia': 3760, 'marti': 3761, 'mesmer': 3762, 'raymond': 3763, 'tiresom': 3764, 'conneri': 3765, 'maid': 3766, 'rubi': 3767, 'duval': 3768, 'chicken': 3769, 'sensat': 3770, 'passeng': 3771, 'vocal': 3772, 'bela': 3773, 'graham': 3774, 'orang': 3775, 'cleverli': 3776, 'employe': 3777, 'dixon': 3778, 'gambl': 3779, 'franki': 3780, 'poem': 3781, 'yawn': 3782, 'whine': 3783, 'volum': 3784, 'giggl': 3785, 'suffic': 3786, 'iran': 3787, 'climact': 3788, 'abraham': 3789, '1968': 3790, 'swallow': 3791, 'inject': 3792, 'sirk': 3793, 'bay': 3794, 'monologu': 3795, 'profan': 3796, 'outing': 3797, 'mute': 3798, 'clone': 3799, 'convincingli': 3800, 'secretli': 3801, 'extens': 3802, 'tube': 3803, 'numb': 3804, 'crystal': 3805, 'amitabh': 3806, 'gerard': 3807, 'habit': 3808, 'calm': 3809, 'lundgren': 3810, 'engross': 3811, 'paranoia': 3812, 'pokemon': 3813, 'scottish': 3814, 'quarter': 3815, 'surpass': 3816, 'trend': 3817, 'lowest': 3818, 'profess': 3819, 'richardson': 3820, 'ethan': 3821, 'fed': 3822, 'franci': 3823, 'abort': 3824, 'chicago': 3825, 'dispos': 3826, 'linger': 3827, 'meander': 3828, 'austen': 3829, 'backward': 3830, 'septemb': 3831, 'grotesqu': 3832, 'poetri': 3833, 'earl': 3834, 'underst': 3835, 'frankenstein': 3836, 'bend': 3837, 'taxi': 3838, 'junior': 3839, 'im': 3840, 'plod': 3841, 'spock': 3842, 'expand': 3843, 'nichola': 3844, 'hum': 3845, 'household': 3846, 'eugen': 3847, 'stallon': 3848, 'tourist': 3849, 'econom': 3850, 'lure': 3851, 'literatur': 3852, 'myth': 3853, 'catchi': 3854, 'muddl': 3855, 'rubber': 3856, 'nostalgia': 3857, 'dysfunct': 3858, 'simplic': 3859, 'cannon': 3860, 'compliment': 3861, 'rant': 3862, 'descent': 3863, 'mundan': 3864, 'spoke': 3865, 'sue': 3866, 'greedi': 3867, 'waitress': 3868, 'instrument': 3869, 'der': 3870, 'bacal': 3871, 'dictat': 3872, 'crucial': 3873, 'damon': 3874, 'hello': 3875, 'phantom': 3876, 'louis': 3877, 'cent': 3878, 'june': 3879, 'alongsid': 3880, 'stale': 3881, 'randi': 3882, 'phoni': 3883, 'occupi': 3884, 'deaf': 3885, 'duck': 3886, 'mortal': 3887, 'firstli': 3888, 'irrelev': 3889, 'equival': 3890, 'omen': 3891, 'recognit': 3892, 'coast': 3893, 'dement': 3894, 'flee': 3895, 'insur': 3896, 'map': 3897, 'sissi': 3898, 'mankind': 3899, 'lang': 3900, 'recognis': 3901, 'eaten': 3902, 'molli': 3903, 'carel': 3904, 'furi': 3905, 'wisdom': 3906, 'daisi': 3907, 'distinguish': 3908, 'dreari': 3909, 'grayson': 3910, 'bike': 3911, 'buffalo': 3912, 'heel': 3913, 'bump': 3914, 'ashley': 3915, 'likewis': 3916, 'rooney': 3917, 'labor': 3918, 'reign': 3919, 'twilight': 3920, 'loyalti': 3921, 'lengthi': 3922, '1973': 3923, 'antwon': 3924, 'drake': 3925, 'cyborg': 3926, 'freez': 3927, 'onlin': 3928, 'blackmail': 3929, 'newli': 3930, 'rude': 3931, 'damm': 3932, 'biko': 3933, 'baddi': 3934, 'worn': 3935, 'inher': 3936, 'chronicl': 3937, 'incorpor': 3938, 'sailor': 3939, 'keith': 3940, 'vein': 3941, 'pink': 3942, 'attribut': 3943, 'butler': 3944, 'startl': 3945, 'prey': 3946, 'provoc': 3947, 'nineti': 3948, 'emphas': 3949, 'analysi': 3950, 'barrymor': 3951, 'basketbal': 3952, 'exposur': 3953, 'approv': 3954, 'boxer': 3955, 'unorigin': 3956, 'ridden': 3957, 'interior': 3958, 'tunnel': 3959, 'proce': 3960, 'indiffer': 3961, 'elm': 3962, 'drift': 3963, 'undeni': 3964, 'degrad': 3965, 'mighti': 3966, 'julian': 3967, 'underli': 3968, 'er': 3969, 'carla': 3970, 'improvis': 3971, 'condemn': 3972, 'robbin': 3973, 'barrel': 3974, 'hypnot': 3975, 'walsh': 3976, 'belushi': 3977, 'unrel': 3978, 'nicol': 3979, 'substitut': 3980, 'predat': 3981, 'stalker': 3982, 'fleet': 3983, 'meyer': 3984, 'bunni': 3985, 'millionair': 3986, 'meg': 3987, 'mormon': 3988, 'simmon': 3989, 'othello': 3990, 'vital': 3991, 'mtv': 3992, 'firm': 3993, 'warmth': 3994, 'reid': 3995, 'enthusiasm': 3996, 'novak': 3997, 'priceless': 3998, 'alarm': 3999, 'exquisit': 4000, 'greed': 4001, 'roof': 4002, 'nyc': 4003, 'edgi': 4004, 'agenda': 4005, 'shove': 4006, 'palac': 4007, 'unawar': 4008, 'hay': 4009, 'errol': 4010, 'disord': 4011, '3d': 4012, 'lampoon': 4013, 'dolph': 4014, 'watson': 4015, 'marion': 4016, 'alison': 4017, 'rukh': 4018, 'profit': 4019, 'preserv': 4020, 'spain': 4021, 'coup': 4022, 'pamela': 4023, 'valentin': 4024, 'what': 4025, 'randomli': 4026, 'peril': 4027, 'drip': 4028, 'campaign': 4029, 'minimum': 4030, 'israel': 4031, 'ponder': 4032, 'petti': 4033, 'peck': 4034, 'testament': 4035, 'iraq': 4036, '1933': 4037, 'gestur': 4038, 'simultan': 4039, 'beatl': 4040, 'eastern': 4041, 'session': 4042, 'angela': 4043, 'showdown': 4044, 'unleash': 4045, 'sergeant': 4046, 'orlean': 4047, '13th': 4048, 'crown': 4049, 'championship': 4050, 'distort': 4051, 'glanc': 4052, 'cassidi': 4053, 'nun': 4054, 'thompson': 4055, 'zizek': 4056, 'unimagin': 4057, 'regist': 4058, 'represent': 4059, 'restrain': 4060, 'bro': 4061, 'contradict': 4062, 'han': 4063, 'wig': 4064, 'rout': 4065, 'crawl': 4066, 'kurosawa': 4067, 'cream': 4068, 'stake': 4069, 'crow': 4070, 'shootout': 4071, 'empathi': 4072, 'travesti': 4073, 'brenda': 4074, 'exposit': 4075, 'din': 4076, 'perpetu': 4077, 'valley': 4078, 'reson': 4079, 'stroke': 4080, 'fido': 4081, 'climat': 4082, 'realm': 4083, 'quinn': 4084, '1984': 4085, 'mon': 4086, 'calib': 4087, 'gentleman': 4088, 'scotland': 4089, 'buster': 4090, 'jan': 4091, 'miyazaki': 4092, 'sabrina': 4093, 'cooki': 4094, 'fuller': 4095, 'shaki': 4096, 'derang': 4097, 'geek': 4098, 'crawford': 4099, 'shoddi': 4100, 'cloud': 4101, 'wax': 4102, 'sucker': 4103, 'censor': 4104, 'passabl': 4105, 'baldwin': 4106, 'warrant': 4107, 'traumat': 4108, 'tacki': 4109, 'pretens': 4110, 'demis': 4111, 'perceiv': 4112, 'stargat': 4113, '1997': 4114, 'ross': 4115, 'femm': 4116, 'painter': 4117, 'compromis': 4118, 'pole': 4119, 'delic': 4120, 'soderbergh': 4121, 'meryl': 4122, 'distress': 4123, 'abomin': 4124, 'unsatisfi': 4125, '1987': 4126, 'monoton': 4127, 'darren': 4128, 'dana': 4129, 'absent': 4130, 'businessman': 4131, 'unseen': 4132, 'spacey': 4133, 'ustinov': 4134, 'mclaglen': 4135, 'josh': 4136, 'sammi': 4137, 'greg': 4138, 'seal': 4139, 'kumar': 4140, 'reluct': 4141, 'correctli': 4142, 'tarantino': 4143, 'primit': 4144, 'polici': 4145, 'fog': 4146, 'clash': 4147, '1993': 4148, 'unravel': 4149, 'nathan': 4150, 'jewel': 4151, 'accuraci': 4152, 'exclus': 4153, 'norm': 4154, 'verbal': 4155, 'dee': 4156, 'judgment': 4157, 'valid': 4158, 'furiou': 4159, 'click': 4160, 'wholli': 4161, 'expedit': 4162, 'deniro': 4163, 'deceas': 4164, 'uncov': 4165, 'tech': 4166, 'fenc': 4167, 'sid': 4168, 'austin': 4169, 'anchor': 4170, 'antonioni': 4171, '1971': 4172, '2008': 4173, 'trait': 4174, 'fart': 4175, 'sheet': 4176, 'ritual': 4177, 'debt': 4178, 'pocket': 4179, 'clerk': 4180, 'malon': 4181, 'dreck': 4182, 'enforc': 4183, 'temper': 4184, 'nicola': 4185, 'logan': 4186, 'darn': 4187, 'fought': 4188, 'mode': 4189, 'hallucin': 4190, 'patienc': 4191, 'seldom': 4192, 'sunni': 4193, 'slam': 4194, 'tax': 4195, 'conduct': 4196, 'sustain': 4197, 'murray': 4198, 'fabric': 4199, 'crippl': 4200, 'roller': 4201, 'joel': 4202, 'alec': 4203, 'vanc': 4204, 'shanghai': 4205, 'wang': 4206, 'bake': 4207, 'unfair': 4208, '3000': 4209, '1995': 4210, 'behold': 4211, 'wretch': 4212, 'sand': 4213, 'bias': 4214, 'sweep': 4215, 'scriptwrit': 4216, 'technicolor': 4217, 'robber': 4218, 'critiqu': 4219, 'fundament': 4220, 'helpless': 4221, 'despis': 4222, 'divid': 4223, 'grief': 4224, 'isabel': 4225, 'pete': 4226, 'clau': 4227, 'canyon': 4228, 'schedul': 4229, 'shell': 4230, 'stuart': 4231, 'rita': 4232, 'legaci': 4233, 'stark': 4234, 'guitar': 4235, 'exhaust': 4236, 'squad': 4237, 'phil': 4238, 'runner': 4239, 'preposter': 4240, 'outlin': 4241, 'conscious': 4242, 'preston': 4243, 'penni': 4244, 'soup': 4245, 'tactic': 4246, 'bridget': 4247, 'vomit': 4248, 'culmin': 4249, 'alicia': 4250, 'implic': 4251, 'passag': 4252, 'liberti': 4253, 'drove': 4254, 'downey': 4255, 'flair': 4256, 'agenc': 4257, 'invad': 4258, 'propos': 4259, 'jacket': 4260, 'connor': 4261, 'gregori': 4262, 'rehash': 4263, 'lacklust': 4264, 'cigarett': 4265, 'bloom': 4266, 'delv': 4267, 'rear': 4268, 'newman': 4269, 'kansa': 4270, 'sugar': 4271, 'alley': 4272, 'restrict': 4273, 'consciou': 4274, 'sniper': 4275, 'russia': 4276, 'marc': 4277, 'boyl': 4278, 'palanc': 4279, 'inabl': 4280, 'jodi': 4281, 'unexpectedli': 4282, 'sentinel': 4283, 'tripe': 4284, 'arrow': 4285, 'delet': 4286, 'vet': 4287, 'aesthet': 4288, '22': 4289, 'rampag': 4290, 'sharon': 4291, 'behaviour': 4292, 'rehears': 4293, 'improb': 4294, 'rod': 4295, 'foxx': 4296, 'tendenc': 4297, 'mccoy': 4298, 'wrench': 4299, 'feat': 4300, 'lush': 4301, 'horn': 4302, 'pale': 4303, 'cap': 4304, 'chainsaw': 4305, 'asylum': 4306, '1936': 4307, 'karl': 4308, 'awhil': 4309, 'yeti': 4310, 'ladder': 4311, 'bacon': 4312, 'kolchak': 4313, 'conscienc': 4314, 'elit': 4315, 'el': 4316, 'thunderbird': 4317, 'newcom': 4318, 'sung': 4319, 'hackney': 4320, 'paradis': 4321, 'prank': 4322, 'underneath': 4323, 'suffici': 4324, 'wildli': 4325, '19th': 4326, '1920': 4327, 'paramount': 4328, 'tomorrow': 4329, 'minu': 4330, 'weav': 4331, 'rhythm': 4332, 'coaster': 4333, 'filler': 4334, 'rumor': 4335, 'scoop': 4336, 'spice': 4337, 'suspicion': 4338, 'amazon': 4339, 'stream': 4340, 'fright': 4341, 'wagner': 4342, 'loneli': 4343, 'shortcom': 4344, 'globe': 4345, 'lurk': 4346, '1988': 4347, 'financ': 4348, 'basing': 4349, '1978': 4350, 'tasteless': 4351, 'hungri': 4352, 'aristocrat': 4353, 'hulk': 4354, 'visitor': 4355, 'recogniz': 4356, 'tierney': 4357, 'heist': 4358, 'smell': 4359, 'choppi': 4360, 'literari': 4361, 'brit': 4362, 'inmat': 4363, 'atroc': 4364, 'paxton': 4365, 'abrupt': 4366, 'springer': 4367, 'counterpart': 4368, 'worship': 4369, 'lectur': 4370, 'grudg': 4371, 'minist': 4372, 'curli': 4373, '75': 4374, 'straightforward': 4375, 'teas': 4376, 'dirt': 4377, 'rub': 4378, 'ingeni': 4379, '1939': 4380, 'entranc': 4381, 'chavez': 4382, 'leigh': 4383, 'beverli': 4384, 'quietli': 4385, 'standout': 4386, 'ram': 4387, 'hopkin': 4388, 'naughti': 4389, 'cancer': 4390, 'en': 4391, '1989': 4392, 'iv': 4393, 'penn': 4394, 'bread': 4395, 'impos': 4396, 'secondari': 4397, 'immers': 4398, 'couch': 4399, 'chamberlain': 4400, 'posey': 4401, 'wwe': 4402, 'esther': 4403, 'injuri': 4404, 'transcend': 4405, 'attenborough': 4406, 'cattl': 4407, 'bernard': 4408, 'watcher': 4409, 'quaid': 4410, 'entitl': 4411, 'variat': 4412, 'duel': 4413, 'laurenc': 4414, 'net': 4415, 'enthral': 4416, 'morbid': 4417, 'policeman': 4418, 'heartfelt': 4419, 'nolan': 4420, 'missil': 4421, 'ratso': 4422, 'yearn': 4423, 'nemesi': 4424, '1986': 4425, 'moreov': 4426, 'sublim': 4427, 'convert': 4428, 'misguid': 4429, 'clan': 4430, 'lindsay': 4431, 'sassi': 4432, 'ace': 4433, 'skeptic': 4434, 'geni': 4435, 'kidman': 4436, 'youngest': 4437, '1979': 4438, 'obstacl': 4439, 'graini': 4440, 'bye': 4441, 'grin': 4442, 'enabl': 4443, 'uncut': 4444, 'steadi': 4445, 'unexplain': 4446, 'moder': 4447, 'hopelessli': 4448, 'egg': 4449, 'cruelti': 4450, 'tyler': 4451, 'reliabl': 4452, 'characteris': 4453, 'setup': 4454, 'out': 4455, 'poe': 4456, 'hk': 4457, 'facil': 4458, 'mytholog': 4459, 'carlito': 4460, 'artsi': 4461, 'spiral': 4462, 'dont': 4463, 'buzz': 4464, 'brood': 4465, 'bean': 4466, 'vader': 4467, 'puppi': 4468, 'diari': 4469, 'rosemari': 4470, 'kitti': 4471, 'heap': 4472, 'hain': 4473, 'preming': 4474, 'sweat': 4475, 'kline': 4476, 'athlet': 4477, 'underworld': 4478, 'narrow': 4479, 'christin': 4480, 'oblig': 4481, 'clueless': 4482, 'despic': 4483, 'martha': 4484, 'bronson': 4485, 'bounc': 4486, 'patricia': 4487, 'baffl': 4488, 'acquaint': 4489, 'niec': 4490, 'exterior': 4491, 'decept': 4492, '1969': 4493, 'effici': 4494, 'weather': 4495, 'bewar': 4496, 'hammi': 4497, 'fuel': 4498, 'gina': 4499, 'disastr': 4500, 'gillian': 4501, 'spontan': 4502, 'brendan': 4503, 'housewif': 4504, 'virtu': 4505, 'shatter': 4506, 'candl': 4507, 'preachi': 4508, 'loath': 4509, 'viewpoint': 4510, 'tick': 4511, 'scar': 4512, 'analyz': 4513, 'harmless': 4514, 'enlist': 4515, 'mayhem': 4516, 'suprem': 4517, 'astound': 4518, 'goof': 4519, 'uh': 4520, 'angst': 4521, '19': 4522, 'trigger': 4523, 'outlaw': 4524, 'taboo': 4525, 'lester': 4526, 'dilemma': 4527, 'dandi': 4528, 'circu': 4529, 'insipid': 4530, 'loi': 4531, 'hepburn': 4532, 'mermaid': 4533, 'sleepwalk': 4534, 'sooner': 4535, 'fontain': 4536, 'rome': 4537, 'injur': 4538, 'renaiss': 4539, 'headach': 4540, '73': 4541, 'biker': 4542, 'stair': 4543, 'spade': 4544, 'phenomenon': 4545, 'zoom': 4546, 'dish': 4547, 'oldest': 4548, 'contempt': 4549, 'overlong': 4550, 'salt': 4551, 'stimul': 4552, 'macho': 4553, 'hokey': 4554, 'scorses': 4555, 'foolish': 4556, 'immatur': 4557, 'claustrophob': 4558, 'amor': 4559, 'filth': 4560, 'fluff': 4561, 'cassavet': 4562, 'ebert': 4563, 'surgeri': 4564, 'dismal': 4565, 'steer': 4566, 'tripl': 4567, 'glorifi': 4568, 'intric': 4569, 'gere': 4570, 'ariel': 4571, 'sox': 4572, 'bent': 4573, 'boston': 4574, 'redund': 4575, 'idol': 4576, 'whore': 4577, 'corbett': 4578, 'hooker': 4579, 'hostag': 4580, 'camcord': 4581, 'slimi': 4582, 'guin': 4583, 'flirt': 4584, 'flashi': 4585, 'mutual': 4586, 'keen': 4587, 'antagonist': 4588, 'fascist': 4589, 'cow': 4590, 'perman': 4591, 'frantic': 4592, 'naschi': 4593, '1981': 4594, 'cush': 4595, 'astronaut': 4596, 'gabl': 4597, 'gasp': 4598, 'joker': 4599, 'margin': 4600, 'harold': 4601, 'conquer': 4602, 'remad': 4603, 'schlock': 4604, 'rhyme': 4605, 'faint': 4606, 'trivia': 4607, 'shield': 4608, 'flag': 4609, 'muscl': 4610, 'corman': 4611, 'messi': 4612, 'dwarf': 4613, 'mount': 4614, 'preced': 4615, 'proport': 4616, 'shred': 4617, 'transplant': 4618, '1976': 4619, 'beard': 4620, 'cohen': 4621, 'assert': 4622, 'spree': 4623, 'down': 4624, 'alvin': 4625, 'widescreen': 4626, 'strongest': 4627, 'radiat': 4628, 'spinal': 4629, 'nolt': 4630, 'obligatori': 4631, 'zane': 4632, 'strive': 4633, 'inflict': 4634, 'bachelor': 4635, '95': 4636, 'www': 4637, 'someday': 4638, 'danish': 4639, 'bitten': 4640, 'wield': 4641, 'neurot': 4642, 'instruct': 4643, 'departur': 4644, 'boob': 4645, 'brush': 4646, 'ritchi': 4647, 'carey': 4648, 'raj': 4649, 'resum': 4650, 'scandal': 4651, 'triangl': 4652, 'discern': 4653, 'info': 4654, 'barn': 4655, 'claud': 4656, 'sensual': 4657, '1945': 4658, 'persuad': 4659, 'off': 4660, 'archiv': 4661, 'deer': 4662, 'fishburn': 4663, 'repris': 4664, 'interestingli': 4665, 'hara': 4666, 'vaniti': 4667, 'mol': 4668, 'divin': 4669, 'mobil': 4670, '28': 4671, 'aborigin': 4672, 'flock': 4673, 'rot': 4674, 'pacif': 4675, 'banter': 4676, 'earnest': 4677, 'hapless': 4678, 'carlo': 4679, 'parson': 4680, 'cliffhang': 4681, 'traffic': 4682, 'jade': 4683, 'cb': 4684, 'luka': 4685, 'prophet': 4686, 'senior': 4687, 'ish': 4688, 'anton': 4689, 'biblic': 4690, 'submit': 4691, 'pixar': 4692, 'fragil': 4693, 'undermin': 4694, 'cycl': 4695, 'casino': 4696, 'vibrant': 4697, 'axe': 4698, 'frontier': 4699, 'heartwarm': 4700, 'recit': 4701, 'wendigo': 4702, 'melissa': 4703, 'kathryn': 4704, 'clad': 4705, 'hilar': 4706, 'helm': 4707, 'mobster': 4708, 'colin': 4709, 'europa': 4710, 'dylan': 4711, 'harrison': 4712, 'proclaim': 4713, 'hug': 4714, 'dim': 4715, 'neill': 4716, 'artwork': 4717, 'timberlak': 4718, 'miracul': 4719, 'bate': 4720, 'dame': 4721, 'cher': 4722, 'pickford': 4723, 'loretta': 4724, 'bikini': 4725, 'http': 4726, 'aris': 4727, 'illus': 4728, 'wardrob': 4729, 'vanessa': 4730, 'uma': 4731, 'flavor': 4732, 'articl': 4733, 'estrang': 4734, 'seedi': 4735, 'eli': 4736, 'legitim': 4737, 'jo': 4738, 'bondag': 4739, 'akin': 4740, 'orphan': 4741, 'breakfast': 4742, 'venom': 4743, 'shepherd': 4744, 'cerebr': 4745, 'lui': 4746, 'antholog': 4747, 'blatantli': 4748, 'mason': 4749, 'holocaust': 4750, 'feast': 4751, 'isra': 4752, 'razor': 4753, 'lucil': 4754, 'vile': 4755, 'static': 4756, 'foil': 4757, 'electron': 4758, 'nope': 4759, 'marlon': 4760, 'misfortun': 4761, 'pc': 4762, 'redneck': 4763, 'mathieu': 4764, 'northern': 4765, 'trier': 4766, 'toronto': 4767, 'choke': 4768, 'sicken': 4769, 'token': 4770, 'jordan': 4771, 'winchest': 4772, 'milo': 4773, 'rooki': 4774, 'alexandr': 4775, 'smack': 4776, 'psych': 4777, 'dudley': 4778, 'howl': 4779, 'leather': 4780, 'deem': 4781, 'glare': 4782, 'gilbert': 4783, 'disregard': 4784, 'fifth': 4785, 'peer': 4786, 'retriev': 4787, 'abund': 4788, 'nightclub': 4789, 'shorter': 4790, 'turd': 4791, 'ideolog': 4792, 'knightley': 4793, 'oppon': 4794, 'frog': 4795, 'outdat': 4796, 'wrestler': 4797, 'swept': 4798, 'charlton': 4799, 'highway': 4800, 'cartoonish': 4801, 'tack': 4802, 'styliz': 4803, 'ceremoni': 4804, 'feminin': 4805, 'boyer': 4806, 'affleck': 4807, 'linear': 4808, 'clinic': 4809, 'comprehend': 4810, 'gunga': 4811, 'audrey': 4812, 'magician': 4813, 'huston': 4814, 'plate': 4815, 'summar': 4816, 'phenomen': 4817, 'cuban': 4818, 'btw': 4819, 'lighter': 4820, '1994': 4821, 'cemeteri': 4822, 'energet': 4823, 'newer': 4824, 'moe': 4825, 'breakdown': 4826, 'lavish': 4827, 'tara': 4828, 'monument': 4829, 'compris': 4830, 'deliver': 4831, 'chip': 4832, 'snatch': 4833, 'uniformli': 4834, 'sleaz': 4835, '4th': 4836, 'bogu': 4837, 'mitch': 4838, 'potter': 4839, 'corn': 4840, 'whack': 4841, 'boo': 4842, 'bastard': 4843, 'evolut': 4844, 'greet': 4845, 'senat': 4846, 'spawn': 4847, 'collector': 4848, 'salman': 4849, 'lifeless': 4850, 'toe': 4851, 'spine': 4852, 'client': 4853, 'goldsworthi': 4854, 'braveheart': 4855, 'einstein': 4856, 'conrad': 4857, '1991': 4858, 'durat': 4859, 'jare': 4860, 'ie': 4861, 'spectacl': 4862, 'firmli': 4863, 'undead': 4864, 'ol': 4865, 'armstrong': 4866, 'evelyn': 4867, 'cecil': 4868, 'clara': 4869, 'liu': 4870, 'inaccuraci': 4871, 'wtf': 4872, 'sorrow': 4873, 'jedi': 4874, 'signal': 4875, 'nina': 4876, 'eleven': 4877, 'bori': 4878, 'randolph': 4879, 'embark': 4880, 'occup': 4881, 'alleg': 4882, 'replay': 4883, 'trauma': 4884, 'judd': 4885, 'gilliam': 4886, 'healthi': 4887, '1974': 4888, '1977': 4889, 'jule': 4890, 'historian': 4891, 'jam': 4892, 'luxuri': 4893, 'belli': 4894, 'constitut': 4895, 'lex': 4896, 'appl': 4897, 'kent': 4898, 'pronounc': 4899, 'bulk': 4900, 'creek': 4901, 'capot': 4902, 'outright': 4903, 'fluid': 4904, 'mcqueen': 4905, 'neatli': 4906, 'undertak': 4907, 'kazan': 4908, 'lauren': 4909, 'spray': 4910, 'kiddi': 4911, 'vignett': 4912, 'antonio': 4913, 'decapit': 4914, 'palm': 4915, 'tokyo': 4916, 'basket': 4917, 'inaccur': 4918, 'congratul': 4919, '1985': 4920, 'curtain': 4921, 'inclus': 4922, 'walt': 4923, 'groan': 4924, 'forgiven': 4925, 'genet': 4926, 'comb': 4927, 'unattract': 4928, 'mum': 4929, 'meal': 4930, 'rosario': 4931, 'bait': 4932, 'lanc': 4933, 'unsuspect': 4934, 'paula': 4935, 'subtli': 4936, 'cape': 4937, 'truman': 4938, 'knee': 4939, 'pioneer': 4940, 'miami': 4941, 'ash': 4942, 'blur': 4943, 'abound': 4944, 'sacrif': 4945, 'porter': 4946, 'relentless': 4947, 'sidewalk': 4948, 'pepper': 4949, 'vain': 4950, 'conan': 4951, 'id': 4952, 'fruit': 4953, 'poker': 4954, 'comprehens': 4955, 'carmen': 4956, 'goldblum': 4957, 'miniseri': 4958, 'roar': 4959, 'galaxi': 4960, 'aussi': 4961, 'propheci': 4962, 'bsg': 4963, 'playboy': 4964, 'profil': 4965, 'scarfac': 4966, 'turtl': 4967, 'dubiou': 4968, 'asset': 4969, 'verg': 4970, 'ingrid': 4971, 'weaker': 4972, 'mice': 4973, 'handicap': 4974, 'detach': 4975, 'jill': 4976, 'reincarn': 4977, 'casper': 4978, 'victorian': 4979, 'cypher': 4980, 'sophi': 4981, 'monti': 4982, 'rapidli': 4983, 'omin': 4984, 'growth': 4985, 'spill': 4986, 'macabr': 4987, 'orchestr': 4988, 'drone': 4989, 'weari': 4990, 'vastli': 4991, 'sparkl': 4992, 'epitom': 4993, 'scariest': 4994, 'substanti': 4995, 'bravo': 4996, '21st': 4997, 'hostil': 4998, 'incorrect': 4999}

**Question:** What are the five most frequently appearing (tokenized) words in the training set? Does it makes sense that these words appear frequently in the training set?_____no_output_____**Answer:**_____no_output_____

# TODO: Use this space to determine the five most frequently appearing words in the training set.

for i, item in enumerate(word_dict):
    if i<5:
        print(item)
    else:
        breakmovi
film
one
like
time

### Save `word_dict`

Later on when we construct an endpoint which processes a submitted review we will need to make use of the `word_dict` which we have created. As such, we will save it to a file now for future use._____no_output_____

data_dir = '../data/pytorch' # The folder we will use for storing data
if not os.path.exists(data_dir): # Make sure that the folder exists
    os.makedirs(data_dir)_____no_output_____with open(os.path.join(data_dir, 'word_dict.pkl'), "wb") as f:
    pickle.dump(word_dict, f)_____no_output_____

### Transform the reviews

Now that we have our word dictionary which allows us to transform the words appearing in the reviews into integers, it is time to make use of it and convert our reviews to their integer sequence representation, making sure to pad or truncate to a fixed length, which in our case is `500`._____no_output_____

def convert_and_pad(word_dict, sentence, pad=500):
    NOWORD = 0 # We will use 0 to represent the 'no word' category
    INFREQ = 1 # and we use 1 to represent the infrequent words, i.e., words not appearing in word_dict

    working_sentence = [NOWORD] * pad

    for word_index, word in enumerate(sentence[:pad]):
        if word in word_dict:
            working_sentence[word_index] = word_dict[word]
        else:
            working_sentence[word_index] = INFREQ

    return working_sentence, min(len(sentence), pad)

def convert_and_pad_data(word_dict, data, pad=500):
    result = []
    lengths = []

    for sentence in data:
        converted, leng = convert_and_pad(word_dict, sentence, pad)
        result.append(converted)
        lengths.append(leng)

    return np.array(result), np.array(lengths)_____no_output_____train_X, train_X_len = convert_and_pad_data(word_dict, train_X)
test_X, test_X_len = convert_and_pad_data(word_dict, test_X)_____no_output_____

As a quick check to make sure that things are working as intended, check to see what one of the reviews in the training set looks like after having been processeed. Does this look reasonable? What is the length of a review in the training set?_____no_output_____

# Use this cell to examine one of the processed reviews to make sure everything is working as intended.

print(train_X[0])
print(train_X_len[0])[   1   37    1  559   17  753   75 2502 2186  148    1   34 1225 4057
  697  673  888   13  610  290  109 2502  936 1127  403    1  732 1681
   40   75    1    1 1891 1469 3665  927  568    1    1 1685    1   21
 2368    1 2771 2936  946    1 1042  489  189 1074  186 2851 4504  990
 1477 1851 1212    4  212 1042  423 1715    4 1074   60  665  243  990
 1477  594  760  243 1593 4584   67 1212    4  208  431   51   11 1212
   67  213 1366    1 3439 2286 1681 2437    1  524 4019 1899  927 1349
 1776  962  243    1  403  976  714   87 3782 3049 3845   79   13 1083
    1   52    1    1  493   13  841    1    1  189    1    1  678 3666
  120 4585    1  431 1470    4  927    1 1769 2038    1  748 1198    1
  549  231  128  330 1852 2502  366 1933 1451 2617    1   72  985    1
 4505 2730  425 1766  453    1    1   80 1386  927  834 3180  777  260
  243  939  211   31   42  774    1 1723   40 1127   25  151   38    2
  232 1380 2258   71   23 1853 1727  141  314  117 3665  927  189 1074
  391 4356  220 2981  509    1 1453 2783 4436  125  753   75  629 2336
 2937 2644  516  840 2502  375  503 4437    4  288  407   44   72  568
  216 1586 1042 1042 1042 1042 1042 1042  118   49  113  580    2   15
    8   69 1206  700    1 1749    1   17    4  639 3440    1  183  774
 4438 3237    2 1042 4504    1   31    1 3401   81  601    1 2315    1
    8    1  927   10    1    1 3028  375 4248 1892 1465   48  138  767
 3416  318 1770    1  129 2075  129 3067 1444  569 1096    3 4505  590
    1  115 1028   26 2124    1 1598 4249  114   18  396  595   91 2387
    1    8 1353 3846  130 2062 1030  777  344 1210    1    1    1  568
  517   31  137 2087 2432 2210    9  257 1128  137  648  271    3  116
  848  306   90  236  419  151  696  820   46    3 1096    3 1369   59
  753   75 2502  218   11   10  559  559  448  355    0    0    0    0
    0    0    0    0    0    0    0    0    0    0    0    0    0    0
    0    0    0    0    0    0    0    0    0    0    0    0    0    0
    0    0    0    0    0    0    0    0    0    0    0    0    0    0
    0    0    0    0    0    0    0    0    0    0    0    0    0    0
    0    0    0    0    0    0    0    0    0    0    0    0    0    0
    0    0    0    0    0    0    0    0    0    0    0    0    0    0
    0    0    0    0    0    0    0    0    0    0    0    0    0    0
    0    0    0    0    0    0    0    0    0    0    0    0    0    0
    0    0    0    0    0    0    0    0    0    0    0    0    0    0
    0    0    0    0    0    0    0    0    0    0]
360
print(test_X[0])
print(test_X_len[0])[  26   52    3   70    7   81 1365   76  392 3454    1   10  979  449
  724   86    3    8   94  225   25   22  293  476  105    9  227    1
 3469  515  185 1007  366  984  121  530    5  274    1    3  312  437
   95  190  355   31   22 1277 1721    1 4596 3609  459  100   19   64
    9  928  560  100  521  118 3454    1  223  225  268    3   10  116
 2379   38  137   18  469  115 1223    6   29 1908    1 2713   38   22
   30   93   44  372  463  426   15   25   38    3    7  225  819    1
    2   57   83   83 1805    1 1471  930   64   77    0    0    0    0
    0    0    0    0    0    0    0    0    0    0    0    0    0    0
    0    0    0    0    0    0    0    0    0    0    0    0    0    0
    0    0    0    0    0    0    0    0    0    0    0    0    0    0
    0    0    0    0    0    0    0    0    0    0    0    0    0    0
    0    0    0    0    0    0    0    0    0    0    0    0    0    0
    0    0    0    0    0    0    0    0    0    0    0    0    0    0
    0    0    0    0    0    0    0    0    0    0    0    0    0    0
    0    0    0    0    0    0    0    0    0    0    0    0    0    0
    0    0    0    0    0    0    0    0    0    0    0    0    0    0
    0    0    0    0    0    0    0    0    0    0    0    0    0    0
    0    0    0    0    0    0    0    0    0    0    0    0    0    0
    0    0    0    0    0    0    0    0    0    0    0    0    0    0
    0    0    0    0    0    0    0    0    0    0    0    0    0    0
    0    0    0    0    0    0    0    0    0    0    0    0    0    0
    0    0    0    0    0    0    0    0    0    0    0    0    0    0
    0    0    0    0    0    0    0    0    0    0    0    0    0    0
    0    0    0    0    0    0    0    0    0    0    0    0    0    0
    0    0    0    0    0    0    0    0    0    0    0    0    0    0
    0    0    0    0    0    0    0    0    0    0    0    0    0    0
    0    0    0    0    0    0    0    0    0    0    0    0    0    0
    0    0    0    0    0    0    0    0    0    0    0    0    0    0
    0    0    0    0    0    0    0    0    0    0    0    0    0    0
    0    0    0    0    0    0    0    0    0    0    0    0    0    0
    0    0    0    0    0    0    0    0    0    0    0    0    0    0
    0    0    0    0    0    0    0    0    0    0    0    0    0    0
    0    0    0    0    0    0    0    0    0    0    0    0    0    0
    0    0    0    0    0    0    0    0    0    0    0    0    0    0
    0    0    0    0    0    0    0    0    0    0]
108

**Question:** In the cells above we use the `preprocess_data` and `convert_and_pad_data` methods to process both the training and testing set. Why or why not might this be a problem?_____no_output_____**Answer:**  Perhaps this could be a problem if these methods are not preserved for use later once the model is deployed. We would have to ensure that both the inputs of the training set and the testing set are treated the same. _____no_output_____## Step 3: Upload the data to S3

As in the XGBoost notebook, we will need to upload the training dataset to S3 in order for our training code to access it. For now we will save it locally and we will upload to S3 later on.

### Save the processed training dataset locally

It is important to note the format of the data that we are saving as we will need to know it when we write the training code. In our case, each row of the dataset has the form `label`, `length`, `review[500]` where `review[500]` is a sequence of `500` integers representing the words in the review._____no_output_____

import pandas as pd

pd.concat([pd.DataFrame(train_y), pd.DataFrame(train_X_len), pd.DataFrame(train_X)], axis=1) \
        .to_csv(os.path.join(data_dir, 'train.csv'), header=False, index=False)_____no_output_____

### Uploading the training data

Next, we need to upload the training data to the SageMaker default S3 bucket so that we can provide access to it while training our model._____no_output_____

import sagemaker

sagemaker_session = sagemaker.Session()

bucket = sagemaker_session.default_bucket()
prefix = 'sagemaker/sentiment_rnn'

role = sagemaker.get_execution_role()_____no_output_____input_data = sagemaker_session.upload_data(path=data_dir, bucket=bucket, key_prefix=prefix)_____no_output_____

**NOTE:** The cell above uploads the entire contents of our data directory. This includes the `word_dict.pkl` file. This is fortunate as we will need this later on when we create an endpoint that accepts an arbitrary review. For now, we will just take note of the fact that it resides in the data directory (and so also in the S3 training bucket) and that we will need to make sure it gets saved in the model directory._____no_output_____## Step 4: Build and Train the PyTorch Model

In the XGBoost notebook we discussed what a model is in the SageMaker framework. In particular, a model comprises three objects

 - Model Artifacts,
 - Training Code, and
 - Inference Code,

each of which interact with one another. In the XGBoost example we used training and inference code that was provided by Amazon. Here we will still be using containers provided by Amazon with the added benefit of being able to include our own custom code.

We will start by implementing our own neural network in PyTorch along with a training script. For the purposes of this project we have provided the necessary model object in the `model.py` file, inside of the `train` folder. You can see the provided implementation by running the cell below._____no_output_____

!pygmentize train/model.py_____no_output_____

The important takeaway from the implementation provided is that there are three parameters that we may wish to tweak to improve the performance of our model. These are the embedding dimension, the hidden dimension and the size of the vocabulary. We will likely want to make these parameters configurable in the training script so that if we wish to modify them we do not need to modify the script itself. We will see how to do this later on. To start we will write some of the training code in the notebook so that we can more easily diagnose any issues that arise.

First we will load a small portion of the training data set to use as a sample. It would be very time consuming to try and train the model completely in the notebook as we do not have access to a gpu and the compute instance that we are using is not particularly powerful. However, we can work on a small bit of the data to get a feel for how our training script is behaving._____no_output_____

import torch
import torch.utils.data

# Read in only the first 250 rows
train_sample = pd.read_csv(os.path.join(data_dir, 'train.csv'), header=None, names=None, nrows=250)

# Turn the input pandas dataframe into tensors
train_sample_y = torch.from_numpy(train_sample[[0]].values).float().squeeze()
train_sample_X = torch.from_numpy(train_sample.drop([0], axis=1).values).long()

# Build the dataset
train_sample_ds = torch.utils.data.TensorDataset(train_sample_X, train_sample_y)
# Build the dataloader
train_sample_dl = torch.utils.data.DataLoader(train_sample_ds, batch_size=50)_____no_output_____

### (TODO) Writing the training method

Next we need to write the training code itself. This should be very similar to training methods that you have written before to train PyTorch models. We will leave any difficult aspects such as model saving / loading and parameter loading until a little later._____no_output_____

def train(model, train_loader, epochs, optimizer, loss_fn, device):
    for epoch in range(1, epochs + 1):
        model.train()
        total_loss = 0
        clip=5

        for batch in train_loader:
            batch_X, batch_y = batch

            batch_X = batch_X.to(device)
            batch_y = batch_y.to(device)

            # TODO: Complete this train method to train the model provided.

            #model.zero_grad()

            output= model(batch_X)

            loss = loss_fn(output.squeeze(), batch_y.float())
            loss.backward()

            nn.utils.clip_grad_norm_(model.parameters(), clip)
            optimizer.step()

            total_loss += loss.data.item()
        print("Epoch: {}, BCELoss: {}".format(epoch, total_loss / len(train_loader)))

        # Citation: https://github.com/udacity/deep-learning-v2-pytorch/blob/master/sentiment-rnn/Sentiment_RNN_Solution.ipynb_____no_output_____

Supposing we have the training method above, we will test that it is working by writing a bit of code in the notebook that executes our training method on the small sample training set that we loaded earlier. The reason for doing this in the notebook is so that we have an opportunity to fix any errors that arise early when they are easier to diagnose._____no_output_____

import torch.nn as nn
import torch.optim as optim
from train.model import LSTMClassifier

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model = LSTMClassifier(32, 100, 5000).to(device)
optimizer = optim.Adam(model.parameters())
loss_fn = torch.nn.BCELoss()

train(model, train_sample_dl, 5, optimizer, loss_fn, device)_____no_output_____

In order to construct a PyTorch model using SageMaker we must provide SageMaker with a training script. We may optionally include a directory which will be copied to the container and from which our training code will be run. When the training container is executed it will check the uploaded directory (if there is one) for a `requirements.txt` file and install any required Python libraries, after which the training script will be run._____no_output_____### (TODO) Training the model

When a PyTorch model is constructed in SageMaker, an entry point must be specified. This is the Python file which will be executed when the model is trained. Inside of the `train` directory is a file called `train.py` which has been provided and which contains most of the necessary code to train our model. The only thing that is missing is the implementation of the `train()` method which you wrote earlier in this notebook.

**TODO**: Copy the `train()` method written above and paste it into the `train/train.py` file where required.

The way that SageMaker passes hyperparameters to the training script is by way of arguments. These arguments can then be parsed and used in the training script. To see how this is done take a look at the provided `train/train.py` file._____no_output_____

from sagemaker.pytorch import PyTorch

estimator = PyTorch(entry_point="train.py",
                    source_dir="train",
                    role=role,
                    framework_version='0.4.0',
                    train_instance_count=1,
                    train_instance_type='ml.m4.xlarge',
                    hyperparameters={
                        'epochs': 10,
                        'hidden_dim': 200,
                    })_____no_output_____estimator.fit({'training': input_data})_____no_output_____

## Step 5: Testing the model

As mentioned at the top of this notebook, we will be testing this model by first deploying it and then sending the testing data to the deployed endpoint. We will do this so that we can make sure that the deployed model is working correctly.

## Step 6: Deploy the model for testing

Now that we have trained our model, we would like to test it to see how it performs. Currently our model takes input of the form `review_length, review[500]` where `review[500]` is a sequence of `500` integers which describe the words present in the review, encoded using `word_dict`. Fortunately for us, SageMaker provides built-in inference code for models with simple inputs such as this.

There is one thing that we need to provide, however, and that is a function which loads the saved model. This function must be called `model_fn()` and takes as its only parameter a path to the directory where the model artifacts are stored. This function must also be present in the python file which we specified as the entry point. In our case the model loading function has been provided and so no changes need to be made.

**NOTE**: When the built-in inference code is run it must import the `model_fn()` method from the `train.py` file. This is why the training code is wrapped in a main guard ( ie, `if __name__ == '__main__':` )

Since we don't need to change anything in the code that was uploaded during training, we can simply deploy the current model as-is.

**NOTE:** When deploying a model you are asking SageMaker to launch an compute instance that will wait for data to be sent to it. As a result, this compute instance will continue to run until *you* shut it down. This is important to know since the cost of a deployed endpoint depends on how long it has been running for.

In other words **If you are no longer using a deployed endpoint, shut it down!**

**TODO:** Deploy the trained model._____no_output_____

from sagemaker.pytorch import PyTorchModel

model_data_loc = "s3://sagemaker-us-west-1-002178010120/sagemaker-pytorch-2020-07-24-16-10-11-403/output/model.tar.gz"

estimator = PyTorchModel(model_data= model_data_loc,
                    entry_point="train.py",
                    source_dir="train",
                    role=role,
                    framework_version='0.4.0',
                    )

Parameter image will be renamed to image_uri in SageMaker Python SDK v2.
estimator_predictor = estimator.deploy(initial_instance_count=1, instance_type='ml.m4.xlarge')_____no_output_____

# TODO: Deploy the trained model

estimator_predictor = estimator.deploy(initial_instance_count=1, instance_type='ml.m4.xlarge')_____no_output_____

import pandas as pd
import sagemaker
from sagemaker.pytorch import PyTorch
import torch
import torch.utils.data
import torch.nn as nn
import torch.optim as optim
from train.model import LSTMClassifier
from time import gmtime, strftime

from sagemaker import get_execution_role
from sagemaker.amazon.amazon_estimator import get_image_uri

import boto3

# This is an object that represents the SageMaker session that we are currently operating in. This
# object contains some useful information that we will need to access later such as our region.
session = sagemaker.Session()

# This is an object that represents the IAM role that we are currently assigned. When we construct
# and launch the training job later we will need to tell it what IAM role it should have. Since our
# use case is relatively simple we will simply assign the training job the role we currently have.
role = get_execution_role()_____no_output_____

model_name = "sagemaker-pytorch-2020-07-24-16-10-11-403"

# As before, we need to give our endpoint configuration a name which should be unique
endpoint_config_name = "sagemaker-pytorch-endpoint-config-" + strftime("%Y-%m-%d-%H-%M-%S", gmtime())

# And then we ask SageMaker to construct the endpoint configuration
endpoint_config_info = session.sagemaker_client.create_endpoint_config(
                            EndpointConfigName = endpoint_config_name,
                            ProductionVariants = [{
                                "InstanceType": "ml.m4.xlarge",
                                "InitialVariantWeight": 1,
                                "InitialInstanceCount": 1,
                                "ModelName": model_name,
                                "VariantName": "AllTraffic"
                            }])_____no_output_____
# load model and deploy to endpoint
endpoint_name = "sagemaker-pytorch-endpoint-" + strftime("%Y-%m-%d-%H-%M-%S", gmtime())

# And then we can deploy our endpoint
endpoint_info = session.sagemaker_client.create_endpoint(
                    EndpointName = endpoint_name,
                    EndpointConfigName = endpoint_config_name)_____no_output_____endpoint_dec = session.wait_for_endpoint(endpoint_name)_____no_output_____## Step 7 - Use the model for testing

Once deployed, we can read in the test data and send it off to our deployed model to get some results. Once we collect all of the results we can determine how accurate our model is._____no_output_____

test_X = pd.concat([pd.DataFrame(test_X_len), pd.DataFrame(test_X)], axis=1)
print(test_X)       0     0     1     2     3     4     5     6     7     8    ...  490  \
0      108    26    52     3    70     7    81  1365    76   392  ...    0
1       64  3106  2129   766   674  3186     1    33    55   888  ...    0
2       64  1426  2245    19  2789     1    34    72    19   102  ...    0
3      187     5    70    76   116   166   484  1914    46    95  ...    0
4       69     6   941   422     1    53  1942   182    55    30  ...    0
...    ...   ...   ...   ...   ...   ...   ...   ...   ...   ...  ...  ...
24995  185    76   210  2043   212  2194   212  2194  1757  2247  ...    0
24996   70   652   291    42   238   318  3131   941     1  1319  ...    0
24997   87     2    54   944  3981     2    21    58     2   317  ...    0
24998   75     4    38  2705     3   220    71    13    23   648  ...    0
24999  173     1  2555   343    97  2368     1     1     1   286  ...    0

       491  492  493  494  495  496  497  498  499
0        0    0    0    0    0    0    0    0    0
1        0    0    0    0    0    0    0    0    0
2        0    0    0    0    0    0    0    0    0
3        0    0    0    0    0    0    0    0    0
4        0    0    0    0    0    0    0    0    0
...    ...  ...  ...  ...  ...  ...  ...  ...  ...
24995    0    0    0    0    0    0    0    0    0
24996    0    0    0    0    0    0    0    0    0
24997    0    0    0    0    0    0    0    0    0
24998    0    0    0    0    0    0    0    0    0
24999    0    0    0    0    0    0    0    0    0

[25000 rows x 501 columns]
print(test_X_len)[108  64  64 ...  87  75 173]
# We split the data into chunks and send each chunk seperately, accumulating the results.

def predict(data, rows=512):
    split_array = np.array_split(data, int(data.shape[0] / float(rows) + 1))
    predictions = np.array([])
    for array in split_array:
        print(array)
        predictions = np.append(predictions, estimator_predictor.predict(array))

    return predictions_____no_output_____def predict(data, rows=512):
    split_array = np.array_split(data, int(data.shape[0] / float(rows) + 1))
    predictions = np.array([])
    for array in split_array:
        print(array)
        for single_array in array:
            print(single_array)
            print(len(single_array))
            output_test = serialize(single_array)
            test = output_test.decode("utf-8")
            test = np.fromstring(test, sep=',')
            print(test)
            print(len(test))
            sagemaker_runtime_predict(serialize(single_array))
            predictions = np.append(predictions, sagemaker_runtime_predict(serialize(single_array)))

    return predictions

def serialize(array):
    # First we need to serialize the input data. In this case we want to send the test data as a csv and
    # so we manually do this. Of course, there are many other ways to do this.
    payload = ','.join([str(entry) for entry in array])
    #payload = ','.join([str(val) for val in array]).encode('utf-8')
    #payload = payload.encode('utf-8')
    #payload = '\n'.join([','.join(row) for row in payload])
    #payload = [','.join(entry) for entry in payload]
    #payload = array.tostring()
    return payload

def sagemaker_runtime_predict(payload):
    # This time we use the sagemaker runtime client rather than the sagemaker client so that we can invoke
    # the endpoint that we created.
    response = session.sagemaker_runtime_client.invoke_endpoint(
                                                EndpointName = endpoint_name,
                                                ContentType = 'text/csv',
                                                #Body = ','.join([str(val) for val in payload]).encode('utf-8'))
                                                Body = payload)

    # We need to make sure that we deserialize the result of our endpoint call.
    result = response['Body'].read().decode("utf-8")
    return np.fromstring(result, sep=',')
    _____no_output_____predictions = predict(test_X)
predictions = [round(num) for num in predictions]     0     0     1    2     3     4     5     6     7    8    ...  490  491  \
0    108    26    52    3    70     7    81  1365    76  392  ...    0    0
1     64  3106  2129  766   674  3186     1    33    55  888  ...    0    0
2     64  1426  2245   19  2789     1    34    72    19  102  ...    0    0
3    187     5    70   76   116   166   484  1914    46   95  ...    0    0
4     69     6   941  422     1    53  1942   182    55   30  ...    0    0
..   ...   ...   ...  ...   ...   ...   ...   ...   ...  ...  ...  ...  ...
506   53   644    89    1    46    63     2   327    62   10  ...    0    0
507   29     1    54   84   557  2627   645   376    93  616  ...    0    0
508  295   693    12    1  1106   986    21    68   389   11  ...    0    0
509  112   452   711   76   284    83     1     1   124   41  ...    0    0
510  114   107    55  500   939   610   687  4682  1457  262  ...    0    0

     492  493  494  495  496  497  498  499
0      0    0    0    0    0    0    0    0
1      0    0    0    0    0    0    0    0
2      0    0    0    0    0    0    0    0
3      0    0    0    0    0    0    0    0
4      0    0    0    0    0    0    0    0
..   ...  ...  ...  ...  ...  ...  ...  ...
506    0    0    0    0    0    0    0    0
507    0    0    0    0    0    0    0    0
508    0    0    0    0    0    0    0    0
509    0    0    0    0    0    0    0    0
510    0    0    0    0    0    0    0    0

[511 rows x 501 columns]
      0     0     1     2     3     4     5     6     7     8    ...  490  \
511   330     1   212   332     4   755   360    15   584    48  ...    0
512   149   224   404  1379   443   146   267   522   802     1  ...    0
513   193     1  1020   164  3811   320  1577  3423   168     2  ...    0
514   192     1   253     4     1  4545   707    66     8   196  ...    0
515    54   121   188    59    42   211   240     3  1852    69  ...    0
...   ...   ...   ...   ...   ...   ...   ...   ...   ...   ...  ...  ...
1017  155   124    63     1     1   532    90     1  1224   452  ...    0
1018   81    21     1    62   113   159   140   309   479  1992  ...    0
1019  135   979     4  2227   875    68    12   159   582   905  ...    0
1020   49  1014     1     1     2   140  1552  3897     1   398  ...    0
1021   98   321  1364  1910    64   172  1249     6    54    61  ...    0

      491  492  493  494  495  496  497  498  499
511     0    0    0    0    0    0    0    0    0
512     0    0    0    0    0    0    0    0    0
513     0    0    0    0    0    0    0    0    0
514     0    0    0    0    0    0    0    0    0
515     0    0    0    0    0    0    0    0    0
...   ...  ...  ...  ...  ...  ...  ...  ...  ...
1017    0    0    0    0    0    0    0    0    0
1018    0    0    0    0    0    0    0    0    0
1019    0    0    0    0    0    0    0    0    0
1020    0    0    0    0    0    0    0    0    0
1021    0    0    0    0    0    0    0    0    0

[511 rows x 501 columns]
from sklearn.metrics import accuracy_score
accuracy_score(test_y, predictions)_____no_output_____print(test_X)       0     0     1     2     3     4     5     6     7     8    ...  490  \
0      108    26    52     3    70     7    81  1365    76   392  ...    0
1       64  3106  2129   766   674  3186     1    33    55   888  ...    0
2       64  1426  2245    19  2789     1    34    72    19   102  ...    0
3      187     5    70    76   116   166   484  1914    46    95  ...    0
4       69     6   941   422     1    53  1942   182    55    30  ...    0
...    ...   ...   ...   ...   ...   ...   ...   ...   ...   ...  ...  ...
24995  185    76   210  2043   212  2194   212  2194  1757  2247  ...    0
24996   70   652   291    42   238   318  3131   941     1  1319  ...    0
24997   87     2    54   944  3981     2    21    58     2   317  ...    0
24998   75     4    38  2705     3   220    71    13    23   648  ...    0
24999  173     1  2555   343    97  2368     1     1     1   286  ...    0

       491  492  493  494  495  496  497  498  499
0        0    0    0    0    0    0    0    0    0
1        0    0    0    0    0    0    0    0    0
2        0    0    0    0    0    0    0    0    0
3        0    0    0    0    0    0    0    0    0
4        0    0    0    0    0    0    0    0    0
...    ...  ...  ...  ...  ...  ...  ...  ...  ...
24995    0    0    0    0    0    0    0    0    0
24996    0    0    0    0    0    0    0    0    0
24997    0    0    0    0    0    0    0    0    0
24998    0    0    0    0    0    0    0    0    0
24999    0    0    0    0    0    0    0    0    0

[25000 rows x 501 columns]

**Question:** How does this model compare to the XGBoost model you created earlier? Why might these two models perform differently on this dataset? Which do *you* think is better for sentiment analysis?_____no_output_____**Answer:**_____no_output_____### (TODO) More testing

We now have a trained model which has been deployed and which we can send processed reviews to and which returns the predicted sentiment. However, ultimately we would like to be able to send our model an unprocessed review. That is, we would like to send the review itself as a string. For example, suppose we wish to send the following review to our model._____no_output_____

test_review = 'The simplest pleasures in life are the best, and this film is one of them. Combining a rather basic storyline of love and adventure this movie transcends the usual weekend fair with wit and unmitigated charm.'

test_review_2 = 'Nothing but a disgusting materialistic pageant of glistening abed remote control greed zombies, totally devoid of any heart or heat. A romantic comedy that has zero romantic chemestry and zero laughs!'_____no_output_____

The question we now need to answer is, how do we send this review to our model?

Recall in the first section of this notebook we did a bunch of data processing to the IMDb dataset. In particular, we did two specific things to the provided reviews.
 - Removed any html tags and stemmed the input
 - Encoded the review as a sequence of integers using `word_dict`

In order process the review we will need to repeat these two steps.

**TODO**: Using the `review_to_words` and `convert_and_pad` methods from section one, convert `test_review` into a numpy array `test_data` suitable to send to our model. Remember that our model expects input of the form `review_length, review[500]`._____no_output_____

# TODO: Convert test_review into a form usable by the model and save the results in test_data
test_data_temp, test_data_len = convert_and_pad(word_dict, review_to_words(test_review), pad=500)

#print(pd.DataFrame(test_data_temp))
#test_data = pd.concat([pd.DataFrame(test_data_len), pd.DataFrame(test_data_temp)], axis=1)

#placeholder = [0]

test_data = np.append(placeholder,test_data_len, axis=None)
test_data = np.append(test_data, test_data_temp, axis = 0)
test_data = test_data[1:]
test_data = np.transpose(pd.DataFrame(test_data))

#test_data = np.append(placeholder,(test_data_len, test_data_temp), axis=0)
#test_data = np.append(test_data, test_data_temp, axis = 0)
#test_data = test_data[1:]

print(test_data)
print(len(test_data))   0    1     2    3    4    5    6    7    8    9    ...  491  492  493  494  \
0   20    1  1373   49   53    3    4  878  173  392  ...    0    0    0    0

   495  496  497  498  499  500
0    0    0    0    0    0    0

[1 rows x 501 columns]
1

Now that we have processed the review, we can send the resulting array to our model to predict the sentiment of the review._____no_output_____

estimator_predictor.predict(test_data)_____no_output_____

Since the return value of our model is close to `1`, we can be certain that the review we submitted is positive._____no_output_____### Delete the endpoint

Of course, just like in the XGBoost notebook, once we've deployed an endpoint it continues to run until we tell it to shut down. Since we are done using our endpoint for now, we can delete it._____no_output_____

estimator_predictor.delete_endpoint()_____no_output_____

## Step 6 (again) - Deploy the model for the web app

Now that we know that our model is working, it's time to create some custom inference code so that we can send the model a review which has not been processed and have it determine the sentiment of the review.

As we saw above, by default the estimator which we created, when deployed, will use the entry script and directory which we provided when creating the model. However, since we now wish to accept a string as input and our model expects a processed review, we need to write some custom inference code.

We will store the code that we write in the `serve` directory. Provided in this directory is the `model.py` file that we used to construct our model, a `utils.py` file which contains the `review_to_words` and `convert_and_pad` pre-processing functions which we used during the initial data processing, and `predict.py`, the file which will contain our custom inference code. Note also that `requirements.txt` is present which will tell SageMaker what Python libraries are required by our custom inference code.

When deploying a PyTorch model in SageMaker, you are expected to provide four functions which the SageMaker inference container will use.
 - `model_fn`: This function is the same function that we used in the training script and it tells SageMaker how to load our model.
 - `input_fn`: This function receives the raw serialized input that has been sent to the model's endpoint and its job is to de-serialize and make the input available for the inference code.
 - `output_fn`: This function takes the output of the inference code and its job is to serialize this output and return it to the caller of the model's endpoint.
 - `predict_fn`: The heart of the inference script, this is where the actual prediction is done and is the function which you will need to complete.

For the simple website that we are constructing during this project, the `input_fn` and `output_fn` methods are relatively straightforward. We only require being able to accept a string as input and we expect to return a single value as output. You might imagine though that in a more complex application the input or output may be image data or some other binary data which would require some effort to serialize.

### (TODO) Writing inference code

Before writing our custom inference code, we will begin by taking a look at the code which has been provided._____no_output_____

!pygmentize serve/predict.pyimport argparse
import json
import os
import pickle
import sys
import sagemaker_containers
import pandas as pd
import numpy as np
import torch
import torch.nn as nn
import torch.optim as optim
import torch.utils.data

from model import LSTMClassifier

from utils import review_to_words, convert_and_pad

def model_fn(model_dir):
    """Load the PyTorch model from the `model_dir` directory."""
    print("Loading model.")

    # First, load the parameters used to create the model.
    model_info = {}
    model_info_path = os.path.join(model_dir, 'model_info.pth')
    with open(model_info_path, 'rb') as f:
        model_info = torch.load(f)

    print("model_info: {}".format(model_info))

    # Determine the device and construct the model.
    device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
    model = LSTMClassifier(model_info['embedding_dim'], model_info['hidden_dim'], model_info['vocab_size'])

    # Load the store model parameters.
    model_path = os.path.join(model_dir, 'model.pth')
    with open(model_path, 'rb') as f:
        model.load_state_dict(torch.load(f))

    # Load the saved word_dict.
    word_dict_path = os.path.join(model_dir, 'word_dict.pkl')
    with open(word_dict_path, 'rb') as f:
        model.word_dict = pickle.load(f)

    model.to(device).eval()

    print("Done loading model.")
    return model

def input_fn(serialized_input_data, content_type):
    print('Deserializing the input data.')
    if content_type == 'text/plain':
        data = serialized_input_data.decode('utf-8')
        return data
    raise Exception('Requested unsupported ContentType in content_type: ' + content_type)

def output_fn(prediction_output, accept):
    print('Serializing the generated output.')
    return str(prediction_output)

def predict_fn(input_data, model):
    print('Inferring sentiment of input data.')

    device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

    if model.word_dict is None:
        raise Exception('Model has not been loaded properly, no word_dict.')

    # TODO: Process input_data so that it is ready to be sent to our model.
    #       You should produce two variables:
    #         data_X   - A sequence of length 500 which represents the converted review
    #         data_len - The length of the review

    data_X = None
    data_len = None

    # Using data_X and data_len we construct an appropriate input tensor. Remember
    # that our model expects input data of the form 'len, review[500]'.
    data_pack = np.hstack((data_len, data_X))
    data_pack = data_pack.reshape(1, -1)

    data = torch.from_numpy(data_pack)
    data = data.to(device)

    # Make sure to put the model into evaluation mode
    model.eval()

    # TODO: Compute the result of applying the model to the input data. The variable `result` should
    #       be a numpy array which contains a single integer which is either 1 or 0

    result = None

    return result

As mentioned earlier, the `model_fn` method is the same as the one provided in the training code and the `input_fn` and `output_fn` methods are very simple and your task will be to complete the `predict_fn` method. Make sure that you save the completed file as `predict.py` in the `serve` directory.

**TODO**: Complete the `predict_fn()` method in the `serve/predict.py` file._____no_output_____### Deploying the model

Now that the custom inference code has been written, we will create and deploy our model. To begin with, we need to construct a new PyTorchModel object which points to the model artifacts created during training and also points to the inference code that we wish to use. Then we can call the deploy method to launch the deployment container.

**NOTE**: The default behaviour for a deployed PyTorch model is to assume that any input passed to the predictor is a `numpy` array. In our case we want to send a string so we need to construct a simple wrapper around the `RealTimePredictor` class to accomodate simple strings. In a more complicated situation you may want to provide a serialization object, for example if you wanted to sent image data._____no_output_____

from sagemaker.predictor import RealTimePredictor
from sagemaker.pytorch import PyTorchModel

class StringPredictor(RealTimePredictor):
    def __init__(self, endpoint_name, sagemaker_session):
        super(StringPredictor, self).__init__(endpoint_name, sagemaker_session, content_type='text/plain')

model = PyTorchModel(model_data=estimator.model_data,
                     role = role,
                     framework_version='0.4.0',
                     entry_point='predict.py',
                     source_dir='serve',
                     predictor_cls=StringPredictor)
predictor = model.deploy(initial_instance_count=1, instance_type='ml.m4.xlarge')Parameter image will be renamed to image_uri in SageMaker Python SDK v2.
'create_image_uri' will be deprecated in favor of 'ImageURIProvider' class in SageMaker Python SDK v2.

### Testing the model

Now that we have deployed our model with the custom inference code, we should test to see if everything is working. Here we test our model by loading the first `250` positive and negative reviews and send them to the endpoint, then collect the results. The reason for only sending some of the data is that the amount of time it takes for our model to process the input and then perform inference is quite long and so testing the entire data set would be prohibitive._____no_output_____

import glob

def test_reviews(data_dir='../data/aclImdb', stop=250):

    results = []
    ground = []

    # We make sure to test both positive and negative reviews
    for sentiment in ['pos', 'neg']:

        path = os.path.join(data_dir, 'test', sentiment, '*.txt')
        files = glob.glob(path)

        files_read = 0

        print('Starting ', sentiment, ' files')

        # Iterate through the files and send them to the predictor
        for f in files:
            with open(f) as review:
                # First, we store the ground truth (was the review positive or negative)
                if sentiment == 'pos':
                    ground.append(1)
                else:
                    ground.append(0)
                # Read in the review and convert to 'utf-8' for transmission via HTTP
                review_input = review.read().encode('utf-8')
                # Send the review to the predictor and store the results
                #output = predictor.predict(review_input).decode("utf-8")
                output = predictor.predict(review_input)
                #print(output)
                #results.append(int(output[7]))
                results.append(int(float(output.decode("utf-8"))))
                #results.append(int(predictor.predict(review_input)))

            # Sending reviews to our endpoint one at a time takes a while so we
            # only send a small number of reviews
            files_read += 1
            if files_read == stop:
                break

    return ground, results_____no_output_____ground, results = test_reviews()Starting  pos  files
b'0.0'
b'0.0'
b'1.0'
b'0.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'0.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'0.0'
b'0.0'
b'1.0'
b'1.0'
b'0.0'
b'1.0'
b'1.0'
b'1.0'
b'0.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'0.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'0.0'
b'0.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'0.0'
b'1.0'
b'1.0'
b'0.0'
b'0.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'0.0'
b'1.0'
b'1.0'
b'0.0'
b'1.0'
b'1.0'
b'0.0'
b'1.0'
b'0.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'0.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'0.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'0.0'
b'1.0'
b'1.0'
b'0.0'
b'1.0'
b'0.0'
b'1.0'
b'0.0'
b'1.0'
b'1.0'
b'0.0'
b'0.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'0.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'0.0'
b'1.0'
b'0.0'
b'0.0'
b'1.0'
b'0.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'0.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'0.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'0.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'0.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'0.0'
b'1.0'
b'0.0'
b'1.0'
b'0.0'
b'0.0'
b'1.0'
b'1.0'
b'1.0'
b'0.0'
b'0.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'0.0'
b'0.0'
b'1.0'
b'0.0'
b'0.0'
b'1.0'
b'1.0'
b'1.0'
b'0.0'
b'0.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'0.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'0.0'
b'1.0'
b'1.0'
b'0.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'1.0'
b'0.0'
b'0.0'
b'1.0'
b'1.0'
Starting  neg  files
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'1.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'1.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'1.0'
b'0.0'
b'1.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'1.0'
b'0.0'
b'1.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'1.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'1.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'1.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'1.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'1.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'1.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'1.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'1.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
b'0.0'
from sklearn.metrics import accuracy_score
accuracy_score(ground, results)_____no_output_____

As an additional test, we can try sending the `test_review` that we looked at earlier._____no_output_____

predictor.predict(test_review)_____no_output_____

Now that we know our endpoint is working as expected, we can set up the web page that will interact with it. If you don't have time to finish the project now, make sure to skip down to the end of this notebook and shut down your endpoint. You can deploy it again when you come back._____no_output_____## Step 7 (again): Use the model for the web app

> **TODO:** This entire section and the next contain tasks for you to complete, mostly using the AWS console.

So far we have been accessing our model endpoint by constructing a predictor object which uses the endpoint and then just using the predictor object to perform inference. What if we wanted to create a web app which accessed our model? The way things are set up currently makes that not possible since in order to access a SageMaker endpoint the app would first have to authenticate with AWS using an IAM role which included access to SageMaker endpoints. However, there is an easier way! We just need to use some additional AWS services.

The diagram above gives an overview of how the various services will work together. On the far right is the model which we trained above and which is deployed using SageMaker. On the far left is our web app that collects a user's movie review, sends it off and expects a positive or negative sentiment in return.

In the middle is where some of the magic happens. We will construct a Lambda function, which you can think of as a straightforward Python function that can be executed whenever a specified event occurs. We will give this function permission to send and recieve data from a SageMaker endpoint.

Lastly, the method we will use to execute the Lambda function is a new endpoint that we will create using API Gateway. This endpoint will be a url that listens for data to be sent to it. Once it gets some data it will pass that data on to the Lambda function and then return whatever the Lambda function returns. Essentially it will act as an interface that lets our web app communicate with the Lambda function.

### Setting up a Lambda function

The first thing we are going to do is set up a Lambda function. This Lambda function will be executed whenever our public API has data sent to it. When it is executed it will receive the data, perform any sort of processing that is required, send the data (the review) to the SageMaker endpoint we've created and then return the result.

#### Part A: Create an IAM Role for the Lambda function

Since we want the Lambda function to call a SageMaker endpoint, we need to make sure that it has permission to do so. To do this, we will construct a role that we can later give the Lambda function.

Using the AWS Console, navigate to the **IAM** page and click on **Roles**. Then, click on **Create role**. Make sure that the **AWS service** is the type of trusted entity selected and choose **Lambda** as the service that will use this role, then click **Next: Permissions**.

In the search box type `sagemaker` and select the check box next to the **AmazonSageMakerFullAccess** policy. Then, click on **Next: Review**.

Lastly, give this role a name. Make sure you use a name that you will remember later on, for example `LambdaSageMakerRole`. Then, click on **Create role**.

#### Part B: Create a Lambda function

Now it is time to actually create the Lambda function.

Using the AWS Console, navigate to the AWS Lambda page and click on **Create a function**. When you get to the next page, make sure that **Author from scratch** is selected. Now, name your Lambda function, using a name that you will remember later on, for example `sentiment_analysis_func`. Make sure that the **Python 3.6** runtime is selected and then choose the role that you created in the previous part. Then, click on **Create Function**.

On the next page you will see some information about the Lambda function you've just created. If you scroll down you should see an editor in which you can write the code that will be executed when your Lambda function is triggered. In our example, we will use the code below.

```python
# We need to use the low-level library to interact with SageMaker since the SageMaker API
# is not available natively through Lambda.
import boto3

def lambda_handler(event, context):

    # The SageMaker runtime is what allows us to invoke the endpoint that we've created.
    runtime = boto3.Session().client('sagemaker-runtime')

    # Now we use the SageMaker runtime to invoke our endpoint, sending the review we were given
    response = runtime.invoke_endpoint(EndpointName = '**ENDPOINT NAME HERE**',    # The name of the endpoint we created
                                       ContentType = 'text/plain',                 # The data format that is expected
                                       Body = event['body'])                       # The actual review

    # The response is an HTTP response whose body contains the result of our inference
    result = response['Body'].read().decode('utf-8')

    return {
        'statusCode' : 200,
        'headers' : { 'Content-Type' : 'text/plain', 'Access-Control-Allow-Origin' : '*' },
        'body' : result
    }
```

Once you have copy and pasted the code above into the Lambda code editor, replace the `**ENDPOINT NAME HERE**` portion with the name of the endpoint that we deployed earlier. You can determine the name of the endpoint using the code cell below._____no_output_____

predictor.endpoint_____no_output_____

Once you have added the endpoint name to the Lambda function, click on **Save**. Your Lambda function is now up and running. Next we need to create a way for our web app to execute the Lambda function.

### Setting up API Gateway

Now that our Lambda function is set up, it is time to create a new API using API Gateway that will trigger the Lambda function we have just created.

Using AWS Console, navigate to **Amazon API Gateway** and then click on **Get started**.

On the next page, make sure that **New API** is selected and give the new api a name, for example, `sentiment_analysis_api`. Then, click on **Create API**.

Now we have created an API, however it doesn't currently do anything. What we want it to do is to trigger the Lambda function that we created earlier.

Select the **Actions** dropdown menu and click **Create Method**. A new blank method will be created, select its dropdown menu and select **POST**, then click on the check mark beside it.

For the integration point, make sure that **Lambda Function** is selected and click on the **Use Lambda Proxy integration**. This option makes sure that the data that is sent to the API is then sent directly to the Lambda function with no processing. It also means that the return value must be a proper response object as it will also not be processed by API Gateway.

Type the name of the Lambda function you created earlier into the **Lambda Function** text entry box and then click on **Save**. Click on **OK** in the pop-up box that then appears, giving permission to API Gateway to invoke the Lambda function you created.

The last step in creating the API Gateway is to select the **Actions** dropdown and click on **Deploy API**. You will need to create a new Deployment stage and name it anything you like, for example `prod`.

You have now successfully set up a public API to access your SageMaker model. Make sure to copy or write down the URL provided to invoke your newly created public API as this will be needed in the next step. This URL can be found at the top of the page, highlighted in blue next to the text **Invoke URL**._____no_output_____## Step 4: Deploying our web app

Now that we have a publicly available API, we can start using it in a web app. For our purposes, we have provided a simple static html file which can make use of the public api you created earlier.

In the `website` folder there should be a file called `index.html`. Download the file to your computer and open that file up in a text editor of your choice. There should be a line which contains **\*\*REPLACE WITH PUBLIC API URL\*\***. Replace this string with the url that you wrote down in the last step and then save the file.

Now, if you open `index.html` on your local computer, your browser will behave as a local web server and you can use the provided site to interact with your SageMaker model.

If you'd like to go further, you can host this html file anywhere you'd like, for example using github or hosting a static site on Amazon's S3. Once you have done this you can share the link with anyone you'd like and have them play with it too!

> **Important Note** In order for the web app to communicate with the SageMaker endpoint, the endpoint has to actually be deployed and running. This means that you are paying for it. Make sure that the endpoint is running when you want to use the web app but that you shut it down when you don't need it, otherwise you will end up with a surprisingly large AWS bill.

**TODO:** Make sure that you include the edited `index.html` file in your project submission._____no_output_____Now that your web app is working, trying playing around with it and see how well it works.

**Question**: Give an example of a review that you entered into your web app. What was the predicted sentiment of your example review?_____no_output_____**Answer: The image may appear broken, so please view screenshot in the Project folder titled image.png. **

![image.png](attachment:image.png)_____no_output_____### Delete the endpoint

Remember to always shut down your endpoint if you are no longer using it. You are charged for the length of time that the endpoint is running so if you forget and leave it on you could end up with an unexpectedly large bill._____no_output_____

predictor.delete_endpoint()_____no_output_____