Skip to content
Snippets Groups Projects
Commit eb502e27 authored by Marco Kuhlmann's avatar Marco Kuhlmann
Browse files

Update the link to the Chocolate Box Challenge

parent 2db58814
No related branches found
No related tags found
No related merge requests found
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
# L4X: Feature engineering for part-of-speech tagging # L4X: Feature engineering for part-of-speech tagging
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
In this lab, you will practice your skills in feature engineering, the task of identifying useful features for a machine learning system. In this lab, you will practice your skills in feature engineering, the task of identifying useful features for a machine learning system.
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## The data set ## The data set
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
The data for this lab and their representation is the same as for the basic lab. The data for this lab and their representation is the same as for the basic lab.
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
class Dataset(): class Dataset():
def __init__(self, filename): def __init__(self, filename):
self.filename = filename self.filename = filename
def __iter__(self): def __iter__(self):
tmp = [] tmp = []
with open(self.filename, 'rt', encoding='utf-8') as lines: with open(self.filename, 'rt', encoding='utf-8') as lines:
for line in lines: for line in lines:
line = line.rstrip() line = line.rstrip()
if line: if line:
tmp.append(tuple(line.split('\t'))) tmp.append(tuple(line.split('\t')))
else: else:
yield tmp yield tmp
tmp = [] tmp = []
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
We load the training data and the development data for this lab: We load the training data and the development data for this lab:
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
train_data = Dataset('train.txt') train_data = Dataset('train.txt')
dev_data = Dataset('dev.txt') dev_data = Dataset('dev.txt')
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## Baseline tagger ## Baseline tagger
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
The baseline tagger that you will use in this lab is a pure Python implementation of the perceptron tagger that was presented in Lecture 4.3 and Lecture 4.4. To understand what the code provided here does, and how it might be extended with new features, you should watch these two lectures. The baseline tagger that you will use in this lab is a pure Python implementation of the perceptron tagger that was presented in Lecture 4.3 and Lecture 4.4. To understand what the code provided here does, and how it might be extended with new features, you should watch these two lectures.
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
### Linear model ### Linear model
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
from collections import defaultdict from collections import defaultdict
class Linear(object): class Linear(object):
def __init__(self, classes): def __init__(self, classes):
self.classes = sorted(classes) self.classes = sorted(classes)
self.weight = {c: defaultdict(float) for c in self.classes} self.weight = {c: defaultdict(float) for c in self.classes}
self.bias = {c: 0.0 for c in self.classes} self.bias = {c: 0.0 for c in self.classes}
def forward(self, features): def forward(self, features):
scores = {} scores = {}
for c in self.classes: for c in self.classes:
scores[c] = self.bias[c] scores[c] = self.bias[c]
for f, v in features.items(): for f, v in features.items():
scores[c] += v * self.weight[c][f] scores[c] += v * self.weight[c][f]
return scores return scores
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
### Perceptron learning algorithm ### Perceptron learning algorithm
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
class PerceptronTrainer(object): class PerceptronTrainer(object):
def __init__(self, model): def __init__(self, model):
self.model = model self.model = model
self._acc = Linear(model.classes) self._acc = Linear(model.classes)
self._counter = 1 self._counter = 1
def update(self, features, gold): def update(self, features, gold):
scores = self.model.forward(features) scores = self.model.forward(features)
pred = max(self.model.classes, key=lambda c: scores[c]) pred = max(self.model.classes, key=lambda c: scores[c])
if pred != gold: if pred != gold:
self.model.bias[gold] += 1 self.model.bias[gold] += 1
self.model.bias[pred] -= 1 self.model.bias[pred] -= 1
self._acc.bias[gold] += self._counter self._acc.bias[gold] += self._counter
self._acc.bias[pred] -= self._counter self._acc.bias[pred] -= self._counter
for f, v in features.items(): for f, v in features.items():
self.model.weight[gold][f] += v self.model.weight[gold][f] += v
self.model.weight[pred][f] -= v self.model.weight[pred][f] -= v
self._acc.weight[gold][f] += v * self._counter self._acc.weight[gold][f] += v * self._counter
self._acc.weight[pred][f] -= v * self._counter self._acc.weight[pred][f] -= v * self._counter
self._counter += 1 self._counter += 1
def finalize(self): def finalize(self):
for c in self.model.classes: for c in self.model.classes:
delta_b = self._acc.bias[c] / self._counter delta_b = self._acc.bias[c] / self._counter
self.model.bias[c] -= delta_b self.model.bias[c] -= delta_b
for feat in self.model.weight[c]: for feat in self.model.weight[c]:
delta_w = self._acc.weight[c][feat] / self._counter delta_w = self._acc.weight[c][feat] / self._counter
self.model.weight[c][feat] -= delta_w self.model.weight[c][feat] -= delta_w
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
### Perceptron tagger ### Perceptron tagger
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
This is the part of the code that you will have to modify. This is the part of the code that you will have to modify.
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
class PerceptronTagger(object): class PerceptronTagger(object):
def __init__(self, tags): def __init__(self, tags):
self.model = Linear(tags) self.model = Linear(tags)
def featurize(self, words, i, pred_tags): def featurize(self, words, i, pred_tags):
# TODO: This is the only method that you are allowed to change! # TODO: This is the only method that you are allowed to change!
feats = [] feats = []
feats.append(words[i]) feats.append(words[i])
feats.append(words[i-1] if i > 0 else '<bos>') feats.append(words[i-1] if i > 0 else '<bos>')
feats.append(words[i+1] if i + 1 < len(words) else '<eos>') feats.append(words[i+1] if i + 1 < len(words) else '<eos>')
feats.append(pred_tags[i-1] if i > 0 else '<bos>') feats.append(pred_tags[i-1] if i > 0 else '<bos>')
return {(i, f): 1 for i, f in enumerate(feats)} return {(i, f): 1 for i, f in enumerate(feats)}
def predict(self, words): def predict(self, words):
pred_tags = [] pred_tags = []
for i, _ in enumerate(words): for i, _ in enumerate(words):
features = self.featurize(words, i, pred_tags) features = self.featurize(words, i, pred_tags)
scores = self.model.forward(features) scores = self.model.forward(features)
pred_tag = max(self.model.classes, key=lambda c: scores[c]) pred_tag = max(self.model.classes, key=lambda c: scores[c])
pred_tags.append(pred_tag) pred_tags.append(pred_tag)
return pred_tags return pred_tags
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
### Training loop ### Training loop
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
from tqdm import tqdm from tqdm import tqdm
def train_perceptron(train_data, n_epochs=1): def train_perceptron(train_data, n_epochs=1):
# Collect the tags in the training data # Collect the tags in the training data
tags = set() tags = set()
for tagged_sentence in train_data: for tagged_sentence in train_data:
words, gold_tags = zip(*tagged_sentence) words, gold_tags = zip(*tagged_sentence)
tags.update(gold_tags) tags.update(gold_tags)
# Initialise and train the perceptron tagger # Initialise and train the perceptron tagger
tagger = PerceptronTagger(tags) tagger = PerceptronTagger(tags)
trainer = PerceptronTrainer(tagger.model) trainer = PerceptronTrainer(tagger.model)
for epoch in range(n_epochs): for epoch in range(n_epochs):
with tqdm(total=sum(1 for s in train_data)) as pbar: with tqdm(total=sum(1 for s in train_data)) as pbar:
for tagged_sentence in train_data: for tagged_sentence in train_data:
words, gold_tags = zip(*tagged_sentence) words, gold_tags = zip(*tagged_sentence)
pred_tags = [] pred_tags = []
for i, gold_tag in enumerate(gold_tags): for i, gold_tag in enumerate(gold_tags):
features = tagger.featurize(words, i, pred_tags) features = tagger.featurize(words, i, pred_tags)
trainer.update(features, gold_tag) trainer.update(features, gold_tag)
pred_tags.append(gold_tag) pred_tags.append(gold_tag)
pbar.update() pbar.update()
trainer.finalize() trainer.finalize()
return tagger return tagger
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## Problem 1: Evaluation ## Problem 1: Evaluation
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
Your first task is to implement a function that computes the accuracy of the tagger on gold-standard data. You have already implemented this function for the base lab, so you should be able to just copy-and-paste it here. Your first task is to implement a function that computes the accuracy of the tagger on gold-standard data. You have already implemented this function for the base lab, so you should be able to just copy-and-paste it here.
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
def accuracy(tagger, gold_data): def accuracy(tagger, gold_data):
# TODO: Replace the next line with your own code # TODO: Replace the next line with your own code
return 0.0 return 0.0
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## Problem 2: Feature engineering ## Problem 2: Feature engineering
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
Your main task now is to try to improve the performance of the perceptron tagger by adding new features. The only part of the code that you are allowed to change is the `featurize` method. Provide a short (ca. 150&nbsp;words) report on what features you added and what results you obtained. Your main task now is to try to improve the performance of the perceptron tagger by adding new features. The only part of the code that you are allowed to change is the `featurize` method. Provide a short (ca. 150&nbsp;words) report on what features you added and what results you obtained.
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
**⚠️ Your submitted notebook must contain output demonstrating at least 91% accuracy on the development set.** **⚠️ Your submitted notebook must contain output demonstrating at least 91% accuracy on the development set.**
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
tagger = train_perceptron(train_data, n_epochs=3) tagger = train_perceptron(train_data, n_epochs=3)
print('{:.4f}'.format(accuracy(tagger, dev_data))) print('{:.4f}'.format(accuracy(tagger, dev_data)))
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
*TODO: Insert your report here* *TODO: Insert your report here*
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## Chocolate Box Challenge ## Chocolate Box Challenge
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
To participate in the [Chocolate Box Challenge](https://www.kaggle.com/t/abb4bfa8d2664ea0b72722fa0ae042f5), run the next code cell to produce a file `submission.csv` and upload this file to Kaggle. To participate in the [Chocolate Box Challenge](https://www.kaggle.com/t/c46f4697d9af4d57af1b0db9fd5ebd67), run the next code cell to produce a file `submission.csv` and upload this file to Kaggle.
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
# Load the test data (without the tags) # Load the test data (without the tags)
test_data = Dataset('test-notags.txt') test_data = Dataset('test-notags.txt')
# Generate submission.csv with results on both the dev data and the test data # Generate submission.csv with results on both the dev data and the test data
with open('submission.csv', 'w') as target: with open('submission.csv', 'w') as target:
target.write('Id,Tag\n') target.write('Id,Tag\n')
for p, data in [('D', dev_data), ('T', test_data)]: for p, data in [('D', dev_data), ('T', test_data)]:
for i, tagged_sentence in enumerate(data): for i, tagged_sentence in enumerate(data):
words, _ = zip(*tagged_sentence) words, _ = zip(*tagged_sentence)
predicted_tags = tagger.predict(words) predicted_tags = tagger.predict(words)
for j, tag in enumerate(predicted_tags): for j, tag in enumerate(predicted_tags):
target.write('{}-{:04d}-{:04d},{}\n'.format(p, i, j, tag)) target.write('{}-{:04d}-{:04d},{}\n'.format(p, i, j, tag))
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
Please observe the following rules for the Chocolate Box Challenge: Please observe the following rules for the Chocolate Box Challenge:
> The point of the challenge is to come up with interesting features. You are not allowed to change the tagger in any other way. > The point of the challenge is to come up with interesting features. You are not allowed to change the tagger in any other way.
Good luck, and may the best team win! 🙂 Good luck, and may the best team win! 🙂
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment