How to Predict Severe Traffic Jams with Python and Recurrent Neural Networks? | by Shuyi Wang | Towards Data Science

In this tutorial, I will show you how to use RNN deep learning model to find patterns from Waze Traffic Open Data of Incidents Report, and predict if severe traffic jams will happen shortly. Interventions can be taken out effectively.
On December 1st, 2018, I participated in a Hackathon Programming competition in UNT Inspire Park at Frisco, TX. The Hackathon is called “HackNTX”.
The Hackathon began at 8 am and finished after 9 pm. The participants can eat snacks and fruits freely, and take walks in the yard to get some fresh air and sunshine. Also, people can talk, discuss and form teams (no more than 5 people each team) freely.
The host provided the competitors various kinds of open data sets, with some pre-defined demo problems. You can choose your own new problem and solve it in the competition.
Waze data, was one of datasets provided.
In China, I never used Waze App for navigation. It’s new to me.
I googled and found the features of Waze. It can not only provide users the ordinary navigation function, but also let the users to report traffic events, so that other users can adjust their routes accordingly.
To me, the most import feature is, when you are trapped in a traffic jam, you can know exactly what happened in the front, such as road under construction, or car accident. In this case, you will be able to have a better estimation and calm down. It will be good for your health.
Since several years ago, Waze cooperated with the government and began to share data. For the government, they can benefit from the instant traffic condition report, and respond to events in time. For the Waze platform, it can integrate the government’s open data, such as road planning, to improve its routing function and make the users happier.
The Waze data provided by the host of HackNTX, is about Traffic Incidents ranging from Nov, 1st till Nov 29th, in DFW area.
The raw data was in TSV format, and the total size is about 300MB.
Each row represents a single incident report, containing the coordinates and time stamp.
During the Exploratory Data Analysis phase, I made several visualizations based on the data.
It was the first time I heard about QGIS, and the software is very powerful. Thank you Jesse for teaching me how to use it!
In the screenshot above, you can see each dot represents a single event. There are too many of them!
As I am not so familiar with QGIS, and Jesse left the competition early in the afternoon, I had to go back to use Python for detailed visualization.
The figure above was made with Geopandas package of Python. It shows three different types of traffic events, namely traffic jam (in red color), accidents (in yellow) and “stopped car on the shoulder” (in blue). Note that they were only extracted from the first 3000 rows in the data set.
As you may already figured out, the amount of red dots (meaning traffic jam) is huge. Traffic jam is indeed a big problem.
I extracted all the unique event types from the data, and got the following list:
As we may learn, traffic jams can be divided into several different levels. The most severe ones, are “large traffic jam” and “huge traffic jam”.
I merged these two types of events to a set A. While the other events can be regarded as set B.
For each event in set A, I back traced 30 minutes, and accumulated every events reported on the same road into a sequence. In total, there are 987 of them. However, some of them are empty lists, meaning nothing was reported before the severe jam, and it happened all suddenly. For these kinds of traffic jam, nobody can predict them, so I decided to remove them, and kept 861 non-empty sequences.
Similarly, I extracted 861 non-empty sequences randomly by back tracing the events coming from set B. Note these sequences did not lead to severe traffic jams.
Now that we have got the sequences as input data, we mark sequences generated from set A as 1, while the others are labeled 0.
Our research question is, can we use a model to classify these sequence data?
The result turned out to be a success. We won the first prize!
Our team, nick named “watch-dumplings”, are formed by Chunying Wang, a visiting PhD student from Wuhan University and me, representing the UNT IIA lab. Each of us got $100. Look how happy we were!
The website of HackNTX soon made a report of the Hackathon competition. Here is the link.
And several days later, UNT reported the news, too.
To me, winning the first prize is almost pure luck. However, I think the model has got potential practical value.
In the latter parts of this article, I will try to show you how to implement the RNN model to classify Waze incident event sequences, using Python and Keras.
To do deep learning, you need GPU or TPU, or your laptop will be tortured. I went to the competition with a fan-less Macbook, and there was no way I can use it to train deep neural networks.
I used Google Colab. It’s quite cool, and the Google people are so generous by providing the users with free GPU and TPU.
Please download and install Google Chrome first, and then click on this link, to install a plugin called Colaboratory.
And you will see the yellow icon of it in the extension bar of Chrome.
I have already uploaded all the code and data of this tutorial on to this github repo.
Please follow the link above, and click on the demo.ipynb.
Now you can click on the icon of Colaboratory, and Chrome will open Google Colab for you automatically, and load this ipynb file into it.
Click on the “COPY TO DRIVE” button I circled with red color in the above screenshot, and Google will create you a copy of the Jupyter Notebook file on your Google Drive.
Go to the menu for “Runtime”, and click on “Change runtime type”.
Double check that the options are set as below:
Save it, and then you are all set.
To run a chunk of code, just hit the run button on the left side.
Let us do it step by step, and I will give you necessary explanations.
We need to load the Pandas package, to handle the tabular data.
import pandas as pd
We will need another package to load data saved by the preprocessing phase. It is called pickle.
import pickle
It can save single or multiple Python data into external file. When you load it back into the program, it will restore the data as it was saved. In this case, it’s easier and more efficient than exchange data with CSV files.
Let’s clone the github repo for this tutorial, and get the data into Google Colab workspace.
!git clone https://github.com/wshuyi/demo_traffic_jam_prediction.git
The data is not so big, and will be downloaded in a short time.
Cloning into 'demo_traffic_jam_prediction'...remote: Enumerating objects: 6, done.[Kremote: Counting objects: 100% (6/6), done.[Kremote: Compressing objects: 100% (4/4), done.[Kremote: Total 6 (delta 0), reused 3 (delta 0), pack-reused 0[KUnpacking objects: 100% (6/6), done.
Let us tell Jupyter Notebook the path of data folder.
from pathlib import Pathdata_dir = Path('demo_traffic_jam_prediction')
We will open the data file and load two different data variables with pickle.
with open(data_dir / 'data.pickle', 'rb') as f:    [event_dict, df] = pickle.load(f)
First, let us look into the dictionary of events called event_dict :
event_dict
Here are all the event types.
{1: 'road closed due to construction', 2: 'traffic jam', 3: 'stopped car on the shoulder', 4: 'road closed', 5: 'other', 6: 'object on roadway', 7: 'major event', 8: 'pothole', 9: 'traffic heavier than normal', 10: 'road construction', 11: 'fog', 12: 'accident', 13: 'slowdown', 14: 'stopped car', 15: 'small traffic jam', 16: 'stopped traffic', 17: 'heavy traffic', 18: 'minor accident', 19: 'medium traffic jam', 20: 'malfunctioning traffic light', 21: 'missing sign on the shoulder', 22: 'animal on the shoulder', 23: 'animal struck', 24: 'large traffic jam', 25: 'hazard on the shoulder', 26: 'hazard on road', 27: 'ice on roadway', 28: 'weather hazard', 29: 'flooding', 30: 'road closed due to hazard', 31: 'hail', 32: 'huge traffic jam'}
Then, let’s see what is in the Dataframe called df.
It’s quite a long table. Let us just display the first 10 rows.
df.head(10)
In each row, there is a corresponding label showing if the sequence of data followed with a severe traffic jam event.
Then we will ask Pandas to show us the last 10 rows.
df.tail(10)
Now that we have loaded the data correctly, we will see which row contains the longest sequence.
We will use a function called idxmax() from Pandas, and it will help us to get the index of the largest value.
max_len_event_id = df.events.apply(len).idxmax()max_len_event_id
Here is the result:
105
Let us dig into the sequence this row has:
max_len_event = df.iloc[max_len_event_id]max_len_event.events
The result is quite a long list.
['stopped car on the shoulder', 'heavy traffic', 'heavy traffic', 'heavy traffic', 'slowdown', 'stopped traffic', 'heavy traffic', 'heavy traffic', 'heavy traffic', 'heavy traffic', 'traffic heavier than normal', 'stopped car on the shoulder', 'traffic jam', 'heavy traffic', 'stopped traffic', 'stopped traffic', 'stopped traffic', 'heavy traffic', 'traffic jam', 'stopped car on the shoulder', 'stopped traffic', 'stopped traffic', 'stopped traffic', 'heavy traffic', 'traffic heavier than normal', 'traffic heavier than normal', 'traffic heavier than normal', 'traffic heavier than normal', 'heavy traffic', 'stopped traffic', 'traffic heavier than normal', 'pothole', 'stopped car on the shoulder', 'traffic jam', 'slowdown', 'stopped traffic', 'heavy traffic', 'traffic heavier than normal', 'traffic jam', 'traffic jam', 'stopped car on the shoulder', 'major event', 'traffic jam', 'traffic jam', 'stopped traffic', 'heavy traffic', 'traffic heavier than normal', 'stopped car on the shoulder', 'slowdown', 'heavy traffic', 'heavy traffic', 'stopped car on the shoulder', 'traffic jam', 'slowdown', 'slowdown', 'heavy traffic', 'stopped car on the shoulder', 'heavy traffic', 'minor accident', 'stopped car on the shoulder', 'heavy traffic', 'stopped car on the shoulder', 'heavy traffic', 'stopped traffic', 'heavy traffic', 'traffic heavier than normal', 'heavy traffic', 'stopped car on the shoulder', 'traffic heavier than normal', 'stopped traffic', 'heavy traffic', 'heavy traffic', 'heavy traffic', 'stopped car on the shoulder', 'slowdown', 'stopped traffic', 'heavy traffic', 'stopped car on the shoulder', 'traffic heavier than normal', 'heavy traffic', 'minor accident', 'major event', 'stopped car on the shoulder', 'stopped car on the shoulder']
If you examine the sequence carefully, you will notice there are hints for a severe traffic jam on this road. However, you need to let the machine to get the “feeling” and classify the sequences automatically.
How long is the longest sequence?
maxlen = len(max_len_event.events)maxlen
Here is the answer:
84
Wow! That is a long list of events!
The computer is not good at reading events names. Let us try to convert the names into numbers, so that the computer can handle the problem better.
To do it efficiently, we need to reverse the dictionary loaded before. That is, to try to convert the “index: event type” format into “event type:index”.
reversed_dict = {}for k, v in event_dict.items():  reversed_dict[v] = k
Let us examine the reversed dictionary.
reversed_dict
Here is the result.
{'accident': 12, 'animal on the shoulder': 22, 'animal struck': 23, 'flooding': 29, 'fog': 11, 'hail': 31, 'hazard on road': 26, 'hazard on the shoulder': 25, 'heavy traffic': 17, 'huge traffic jam': 32, 'ice on roadway': 27, 'large traffic jam': 24, 'major event': 7, 'malfunctioning traffic light': 20, 'medium traffic jam': 19, 'minor accident': 18, 'missing sign on the shoulder': 21, 'object on roadway': 6, 'other': 5, 'pothole': 8, 'road closed': 4, 'road closed due to construction': 1, 'road closed due to hazard': 30, 'road construction': 10, 'slowdown': 13, 'small traffic jam': 15, 'stopped car': 14, 'stopped car on the shoulder': 3, 'stopped traffic': 16, 'traffic heavier than normal': 9, 'traffic jam': 2, 'weather hazard': 28}
We made it.
Now we will need to compose a function, to convert a list of events, and return us a list of numbers.
def map_event_list_to_idxs(event_list):  list_idxs = []  for event in (event_list):    idx = reversed_dict[event]    list_idxs.append(idx)  return list_idxs
Let us try the function on our longest list.
map_event_list_to_idxs(max_len_event.events)
The result is:
[3, 17, 17, 17, 13, 16, 17, 17, 17, 17, 9, 3, 2, 17, 16, 16, 16, 17, 2, 3, 16, 16, 16, 17, 9, 9, 9, 9, 17, 16, 9, 8, 3, 2, 13, 16, 17, 9, 2, 2, 3, 7, 2, 2, 16, 17, 9, 3, 13, 17, 17, 3, 2, 13, 13, 17, 3, 17, 18, 3, 17, 3, 17, 16, 17, 9, 17, 3, 9, 16, 17, 17, 17, 3, 13, 16, 17, 3, 9, 17, 18, 7, 3, 3]
Now we load numpy and some utility functions from Keras.
import numpy as npfrom keras.utils import to_categoricalfrom keras.preprocessing.sequence import pad_sequences
We need to figure out how many different event types we have got.
len(event_dict)
Here is the result:
32
Let us convert the all the sequence of events into lists of numbers.
df.events.apply(map_event_list_to_idxs)
The result is:
0      [9, 17, 18, 14, 13, 17, 3, 13, 16, 3, 17, 17, ...1                                             [2, 10, 3]2                                                    [2]3                                                    [2]4                               [2, 2, 2, 2, 2, 2, 2, 9]5                                             [3, 2, 17]6                                             [3, 2, 17]7                        [2, 15, 2, 17, 2, 2, 13, 17, 2]8                                  [17, 2, 2, 16, 17, 2]9                                  [17, 2, 2, 16, 17, 2]10     [17, 16, 17, 2, 17, 3, 17, 17, 16, 17, 16, 18,...11                                                  [17]12                                                  [17]13                                              [24, 24]14                                    [24, 2, 24, 24, 2]15                                    [24, 2, 24, 24, 2]16     [2, 10, 2, 2, 2, 18, 16, 16, 7, 2, 16, 2, 2, 9...17     [2, 10, 2, 2, 2, 18, 16, 16, 7, 2, 16, 2, 2, 9...18                               [24, 24, 24, 16, 2, 16]19                               [24, 24, 24, 16, 2, 16]20                                                [2, 2]21                                            [2, 16, 2]22                                            [2, 16, 2]23                                                [2, 2]24                                                [2, 2]25                                              [24, 24]26                                                [2, 2]27                                         [2, 2, 2, 17]28                                            [2, 19, 2]29                                                  [24]                             ...831                     [9, 9, 9, 2, 9, 9, 17, 2, 9, 17]832                                            [3, 3, 3]833                                 [2, 9, 2, 17, 17, 2]834       [3, 3, 17, 3, 13, 3, 3, 23, 9, 3, 3, 25, 3, 3]835      [3, 17, 9, 14, 9, 17, 14, 9, 2, 9, 3, 2, 2, 17]836                                                  [2]837         [17, 2, 16, 3, 9, 17, 17, 17, 13, 17, 9, 17]838    [13, 17, 17, 3, 3, 16, 17, 16, 17, 16, 3, 9, 1...839                                                  [2]840                                                  [3]841                                                  [2]842    [17, 17, 17, 3, 17, 23, 16, 17, 17, 3, 2, 13, ...843                                               [3, 3]844                                                  [2]845                     [2, 17, 2, 2, 2, 2, 2, 17, 2, 2]846                                   [7, 17, 3, 18, 17]847                                            [3, 3, 3]848    [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, ...849                                               [2, 2]850          [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 13, 3, 2]851                                            [2, 2, 2]852                                          [16, 2, 16]853                [3, 16, 5, 3, 17, 3, 16, 9, 3, 2, 17]854                                                 [16]855    [3, 3, 3, 3, 3, 3, 3, 3, 2, 13, 3, 6, 3, 6, 3,...856                    [17, 17, 17, 2, 3, 2, 2, 2, 2, 2]857                                               [2, 2]858                                  [2, 2, 9, 17, 2, 2]859                            [17, 3, 2, 2, 2, 2, 2, 2]860    [17, 3, 3, 17, 3, 17, 2, 3, 18, 14, 3, 3, 16, ...Name: events, Length: 1722, dtype: object
As human beings, it is hard for us to recognize the meaning of each number represents. However, for the computer, it is much easier.
We name the result list as sequences, and display for first five rows.
sequences = df.events.apply(map_event_list_to_idxs).tolist()sequences[:5]
Here is the result:
[[9,  17,  18,  14,  13,  17,  3,  13,  16,  3,  17,  17,  16,  3,  16,  17,  9,  17,  2,  17,  2,  7,  16,  17,  17,  17,  17,  13,  5,  17,  9,  9,  16,  16,  3], [2, 10, 3], [2], [2], [2, 2, 2, 2, 2, 2, 2, 9]]
Note the first row is much longer than the following ones.
However, to apply a sequence model on the data, we need to make sure all the input sequences share the same length. Hence, we use the length of the longest sequence as the max length, and fill other shorter sequences with 0s from the beginning.
data = pad_sequences(sequences, maxlen=maxlen)data
Here are the padded sequences:
array([[ 0,  0,  0, ..., 16, 16,  3],       [ 0,  0,  0, ...,  2, 10,  3],       [ 0,  0,  0, ...,  0,  0,  2],       ...,       [ 0,  0,  0, ..., 17,  2,  2],       [ 0,  0,  0, ...,  2,  2,  2],       [ 0,  0,  0, ...,  3,  3,  2]], dtype=int32)
Now all the sequences have the same length.
We will need to get the label column, and save it into a variable called labels.
labels = np.array(df.label)
As we need to use several random functions, to keep your running result identical to mine, we will specify the random seed value as 12.
np.random.seed(12)
When you finished the first running of the code, feel free to modify it.
We shuffle the sequences along with their corresponding labels.
indices = np.arange(data.shape[0])np.random.shuffle(indices)data = data[indices]labels = labels[indices]
The training set will contain 80% of the data, while the other 20% goes into the validation set.
training_samples = int(len(indices) * .8)validation_samples = len(indices) - training_samples
The following codes divide the data into training and validation sets, along with the labels.
X_train = data[:training_samples]y_train = labels[:training_samples]X_valid = data[training_samples: training_samples + validation_samples]y_valid = labels[training_samples: training_samples + validation_samples]
Let us show the content of training data:
X_train
Here is the result.
array([[ 0,  0,  0, ..., 15, 15,  3],       [ 0,  0,  0, ...,  0,  2,  2],       [ 0,  0,  0, ...,  0,  0, 16],       ...,       [ 0,  0,  0, ...,  2, 15, 16],       [ 0,  0,  0, ...,  2,  2,  2],       [ 0,  0,  0, ...,  0,  0,  2]], dtype=int32)
Please do note that as we filled the sequences with 0 as padding value, now we have 33, instead of 32 event types.
So the number of event types will be set to 33.
num_events = len(event_dict) + 1
If we simply put the numbers into classification model, it will regard each number as a continuous value. However, they are not. So we will let the numbers go through an Embedding layer, and convert each number (representing a certain type of event) into a vector. Each vector, will contain 20 scalars.
embedding_dim = 20
The initial embedding matrix will be generated randomly.
embedding_matrix = np.random.rand(num_events, embedding_dim)
Finally, we can build a model now.
We use the Sequential model in Keras, and put different layers one by one, as we play with legos.
The first layer is Embedding Layer, then a LSTM Layer follows, the last layer is a dense one, whose activation function is sigmoid, to make binary classification.
from keras.models import Sequentialfrom keras.layers import Embedding, Flatten, Dense, LSTMunits = 32model = Sequential()model.add(Embedding(num_events, embedding_dim))model.add(LSTM(units))model.add(Dense(1, activation='sigmoid'))
If you are not familiar with Keras, I recommend you to read “Deep Learning with Python” by François Chollet, the creater of Keras.
The next step is to handle the parameters in the Embedding layer. For now, we just load in the initial embedding matrix generated randomly, and won’t let the training process change the weights in Embedding Layer.
model.layers[0].set_weights([embedding_matrix])model.layers[0].trainable = False
Then, we train the model, and save the model into a h5 file.
model.compile(optimizer='rmsprop',              loss='binary_crossentropy',              metrics=['acc'])history = model.fit(X_train, y_train,                    epochs=50,                    batch_size=32,                    validation_data=(X_valid, y_valid))model.save("mymodel_embedding_untrainable.h5")
With the strong support of TPU, the training is quite fast.
After the model is trained, let us visualize the curves of accuracy and loss with matplotlib.
import matplotlib.pyplot as pltacc = history.history['acc']val_acc = history.history['val_acc']loss = history.history['loss']val_loss = history.history['val_loss']epochs = range(1, len(acc) + 1)plt.plot(epochs, acc, 'bo', label='Training acc')plt.plot(epochs, val_acc, 'b', label='Validation acc')plt.title('Training and validation accuracy')plt.legend()plt.figure()plt.plot(epochs, loss, 'bo', label='Training loss')plt.plot(epochs, val_loss, 'b', label='Validation loss')plt.title('Training and validation loss')plt.legend()plt.show()
This is the curve of accuracy.
As you can see, it is not bad. If we use a dummy model to predict everything as label 0 (or all as 1), the accuracy will stay at 0.50. So our model, apparently, has captured some pattern, and out-performed the dummy one.
However, it is very unstable.
Then let us look into the curve of loss.
As you may find out, it is not good. When the loss of training went down, the loss on validation set bumped, and there is no significant trend of convergence.
It is more important to find out the reason.
Note that we used a randomly initialized Embedding Matrix which stayed static during the training phase. It may lead us into trouble.
So next step, we can do an experiment to allow the Embedding layer be trained and adjusted.
from keras.models import Sequentialfrom keras.layers import Embedding, Flatten, Dense, LSTMunits = 32model = Sequential()model.add(Embedding(num_events, embedding_dim))model.add(LSTM(units))model.add(Dense(1, activation='sigmoid'))
The only different in the code, is that parameter trainable was set to True.
model.layers[0].set_weights([embedding_matrix])model.layers[0].trainable = True
Let us compile the model and run it over again.
model.compile(optimizer='rmsprop',              loss='binary_crossentropy',              metrics=['acc'])history = model.fit(X_train, y_train,                    epochs=50,                    batch_size=32,                    validation_data=(X_valid, y_valid))model.save("mymodel_embedding_trainable.h5")
And we draw the curves of accuracy and loss, too.
import matplotlib.pyplot as pltacc = history.history['acc']val_acc = history.history['val_acc']loss = history.history['loss']val_loss = history.history['val_loss']epochs = range(1, len(acc) + 1)plt.plot(epochs, acc, 'bo', label='Training acc')plt.plot(epochs, val_acc, 'b', label='Validation acc')plt.title('Training and validation accuracy')plt.legend()plt.figure()plt.plot(epochs, loss, 'bo', label='Training loss')plt.plot(epochs, val_loss, 'b', label='Validation loss')plt.title('Training and validation loss')plt.legend()plt.show()
The curve of accuracy is shown as below.
As you can see, it got better. The fluctuation of validation accuracy curve went down, while the validation accuracy got higher than 0.75.
This model is, to some extent, more valuable.
However, we should not draw a conclusion so soon. If you look into the curve of loss, you cannot be so optimistic.
Since half-way, the trends of loss on different sets went to different direction.
It is a hint of over-fitting.
Over-fitting always indicates the training data is not enough for a complex model.
You can either add more data for the training, or bring down the complexity.
The first approach is not so applicable for now, because we have only got a dataset ranging 29 days in November.
However, to bring down the complexity of the model, it can be done easily with Dropout.
When you use Dropout, the model will randomly select a certain proportion (you call the shots) of neurons, and set the weights of them to zero in the training phase, so that they can be regarded as “removed” from the network, and the complexity became lower.
Note in validation phase, the model will use all neurons without any Dropout.
We will add two parameters related with Dropouts. To do this, we use dropout=0.2, recurrent_dropout=0.2 when defining the LSTM layer.
from keras.models import Sequentialfrom keras.layers import Embedding, Flatten, Dense, LSTMunits = 32model = Sequential()model.add(Embedding(num_events, embedding_dim))model.add(LSTM(units, dropout=0.2, recurrent_dropout=0.2))model.add(Dense(1, activation='sigmoid'))
We will keep the parameter trainable of Embedding Layer to True.
model.layers[0].set_weights([embedding_matrix])model.layers[0].trainable = True
Let us run the training again.
model.compile(optimizer='rmsprop',              loss='binary_crossentropy',              metrics=['acc'])history = model.fit(X_train, y_train,                    epochs=50,                    batch_size=32,                    validation_data=(X_valid, y_valid))model.save("mymodel_embedding_trainable_with_dropout.h5")
There is no modification of the visualization part.
import matplotlib.pyplot as pltacc = history.history['acc']val_acc = history.history['val_acc']loss = history.history['loss']val_loss = history.history['val_loss']epochs = range(1, len(acc) + 1)plt.plot(epochs, acc, 'bo', label='Training acc')plt.plot(epochs, val_acc, 'b', label='Validation acc')plt.title('Training and validation accuracy')plt.legend()plt.figure()plt.plot(epochs, loss, 'bo', label='Training loss')plt.plot(epochs, val_loss, 'b', label='Validation loss')plt.title('Training and validation loss')plt.legend()plt.show()
From the accuracy curve, you may see nothing exciting.
However, when you look into the curve of loss, you’ll see significant improvement.
The curve of validation loss is smoother, and much closer to the trend of training loss.
Over-fitting has been taken care of, and the model is now more stable and generalizable to unseen data.
The Traffic Administration can then use the model to predict the happening of severe traffic jam with the Waze open data of incidents report. The expectation of model accuracy is about 75%.
Maybe in this way, some severe traffic jam will not happen at all, thanks to the preventions.
Hope you can get the following points from this tutorial.
Sequence model, such as RNN and LSTM, can not only be used on texts, but other sequential data as well.
You can use Embedding layer in these kinds of tasks, even though they don’t have pre-trained word-embedding models, such as word2vec, glove, or fasttext. Make sure you set the weights of embedding layer trainable.
You can try to beat over-fitting with several different methods. Dropout is one of them. In our case, it is effective.
Hope you can handle your own classification task with sequential data now.
Happy Deep Learning!
My other Tutorials on Deep Learning:
Deep Learning with Python and fast.ai, Part 1: Image classification with pre-trained model
Deep Learning with Python and fast.ai, Part 2: NLP Classification with Transfer Learning
Deep Learning with Python, Part 0: Setup Fast.ai 1.0 on Google Cloud
How to Accelerate Your Python Deep Learning with Cloud GPU?