Fast.ai v3 2019课程中文版笔记

IMDB

三行魔法代码

三行魔法代码

%reload_ext autoreload
%autoreload 2
%matplotlib inline
所需library

所需library

from fastai.text import *

Preparing the data

介绍数据集

介绍数据集

First let’s download the dataset we are going to study. The dataset has been curated by Andrew Maas et al. and contains a total of 100,000 reviews on IMDB. 25,000 of them are labelled as positive and negative for training, another 25,000 are labelled for testing (in both cases they are highly polarized). The remaning 50,000 is an additional unlabelled data (but we will find a use for it nonetheless).

We’ll begin with a sample we’ve prepared for you, so that things run quickly before going over the full dataset.

查看数据文件夹

查看数据文件夹

path = untar_data(URLs.IMDB_SAMPLE)
path.ls()
[PosixPath('/home/ubuntu/notebooks/data/imdb_sample/data_clas_export.pkl'),
 PosixPath('/home/ubuntu/notebooks/data/imdb_sample/export_lm.pkl'),
 PosixPath('/home/ubuntu/notebooks/data/imdb_sample/export.pkl'),
 PosixPath('/home/ubuntu/notebooks/data/imdb_sample/texts.csv'),
 PosixPath('/home/ubuntu/notebooks/data/imdb_sample/data_lm_export.pkl'),
 PosixPath('/home/ubuntu/notebooks/data/imdb_sample/export_clas.pkl'),
 PosixPath('/home/ubuntu/notebooks/data/imdb_sample/models'),
 PosixPath('/home/ubuntu/notebooks/data/imdb_sample/save_data_clas.pkl')]
查看csv

查看csv

It only contains one csv file, let’s have a look at it.

df = pd.read_csv(path/'texts.csv')
df.head()
.dataframe tbody tr th:only-of-type { vertical-align: middle; }
.dataframe tbody tr th {
    vertical-align: top;
}

.dataframe thead th {
    text-align: right;
}
label text is_valid
0 negative Un-bleeping-believable! Meg Ryan doesn't even ... False
1 positive This is a extremely well-made film. The acting... False
2 negative Every once in a long while a movie will come a... False
3 positive Name just says it all. I watched this movie wi... False
4 negative This movie succeeds at being one of the most u... False
df['text'][1]
'This is a extremely well-made film. The acting, script and camera-work are all first-rate. The music is good, too, though it is mostly early in the film, when things are still relatively cheery. There are no really superstars in the cast, though several faces will be familiar. The entire cast does an excellent job with the script.<br /><br />But it is hard to watch, because there is no good end to a situation like the one presented. It is now fashionable to blame the British for setting Hindus and Muslims against each other, and then cruelly separating them into two countries. There is some merit in this view, but it\'s also true that no one forced Hindus and Muslims in the region to mistreat each other as they did around the time of partition. It seems more likely that the British simply saw the tensions between the religions and were clever enough to exploit them to their own ends.<br /><br />The result is that there is much cruelty and inhumanity in the situation and this is very unpleasant to remember and to see on the screen. But it is never painted as a black-and-white case. There is baseness and nobility on both sides, and also the hope for change in the younger generation.<br /><br />There is redemption of a sort, in the end, when Puro has to make a hard choice between a man who has ruined her life, but also truly loved her, and her family which has disowned her, then later come looking for her. But by that point, she has no option that is without great pain for her.<br /><br />This film carries the message that both Muslims and Hindus have their grave faults, and also that both can be dignified and caring people. The reality of partition makes that realisation all the more wrenching, since there can never be real reconciliation across the India/Pakistan border. In that sense, it is similar to "Mr & Mrs Iyer".<br /><br />In the end, we were glad to have seen the film, even though the resolution was heartbreaking. If the UK and US could deal with their own histories of racism with this kind of frankness, they would certainly be better off.'
从CSV中创建TextDataBunch

从CSV中创建TextDataBunch

It contains one line per review, with the label (‘negative’ or ‘positive’), the text and a flag to determine if it should be part of the validation set or the training set. If we ignore this flag, we can create a DataBunch containing this data in one line of code:

data_lm = TextDataBunch.from_csv(path, 'texts.csv')
TextDataBunch背后工作流程

TextDataBunch背后工作流程

By executing this line a process was launched that took a bit of time. Let’s dig a bit into it. Images could be fed (almost) directly into a model because they’re just a big array of pixel values that are floats between 0 and 1. A text is composed of words, and we can’t apply mathematical functions to them directly. We first have to convert them to numbers. This is done in two differents steps: tokenization and numericalization. A TextDataBunch does all of that behind the scenes for you.

Before we delve into the explanations, let’s take the time to save the things that were calculated.

保存和加载处理好的语言模型

保存和加载处理好的语言模型

data_lm.save()

Next time we launch this notebook, we can skip the cell above that took a bit of time (and that will take a lot more when you get to the full dataset) and load those results like this:

data = load_data(path)

Tokenization

什么是tokenization

什么是tokenization

The first step of processing we make the texts go through is to split the raw sentences into words, or more exactly tokens. The easiest way to do this would be to split the string on spaces, but we can be smarter:

  • we need to take care of punctuation
  • some words are contractions of two different words, like isn’t or don’t
  • we may need to clean some parts of our texts, if there’s HTML code for instance

To see what the tokenizer had done behind the scenes, let’s have a look at a few texts in a batch.

创建并展示TextClasDataBunch

创建并展示TextClasDataBunch

data = TextClasDataBunch.from_csv(path, 'texts.csv')
data.show_batch()
text target
xxbos xxmaj raising xxmaj victor xxmaj vargas : a xxmaj review \n \n xxmaj you know , xxmaj raising xxmaj victor xxmaj vargas is like sticking your hands into a big , steaming bowl of xxunk . xxmaj it 's warm and gooey , but you 're not sure if it feels right . xxmaj try as i might , no matter how warm and gooey xxmaj raising xxmaj negative
xxbos xxup the xxup shop xxup around xxup the xxup corner is one of the sweetest and most feel - good romantic comedies ever made . xxmaj there 's just no getting around that , and it 's hard to actually put one 's feeling for this film into words . xxmaj it 's not one of those films that tries too hard , nor does it come up with positive
xxbos xxmaj now that xxmaj che(2008 ) has finished its relatively short xxmaj australian cinema run ( extremely limited xxunk screen in xxmaj sydney , after xxunk ) , i can xxunk join both xxunk of " xxmaj at xxmaj the xxmaj movies " in taking xxmaj steven xxmaj soderbergh to task . \n \n xxmaj it 's usually satisfying to watch a film director change his style / negative
xxbos xxmaj this film sat on my xxmaj tivo for weeks before i watched it . i dreaded a self - indulgent xxunk flick about relationships gone bad . i was wrong ; this was an xxunk xxunk into the screwed - up xxunk of xxmaj new xxmaj yorkers . \n \n xxmaj the format is the same as xxmaj max xxmaj xxunk ' " xxmaj la xxmaj ronde positive
xxbos xxmaj many neglect that this is n't just a classic due to the fact that it 's the first xxup 3d game , or even the first xxunk - up . xxmaj it 's also one of the first stealth games , one of the xxunk definitely the first ) truly claustrophobic games , and just a pretty well - xxunk gaming experience in general . xxmaj with graphics positive

The texts are truncated at 100 tokens for more readability. We can see that it did more than just split on space and punctuation symbols:

  • the “'s” are grouped together in one token
  • the contractions are separated like this: “did”, “n’t”
  • content has been cleaned for any HTML symbol and lower cased
  • there are several special tokens (all those that begin by xx), to replace unknown tokens (see below) or to introduce different text fields (here we only have one).

Numericalization

什么是numericalization

什么是numericalization

Once we have extracted tokens from our texts, we convert to integers by creating a list of all the words used. We only keep the ones that appear at least twice with a maximum vocabulary size of 60,000 (by default) and replace the ones that don’t make the cut by the unknown token UNK.

The correspondance from ids to tokens is stored in the vocab attribute of our datasets, in a dictionary called itos (for int to string).

查看 UNK

查看 UNK

data.vocab.itos[:10]
['xxunk',
 'xxpad',
 'xxbos',
 'xxfld',
 'xxmaj',
 'xxup',
 'xxrep',
 'xxwrep',
 'the',
 '.']
查看数据data

查看数据data

And if we look at what a what’s in our datasets, we’ll see the tokenized text as a representation:

data.train_ds[0][0]
Text xxbos i know that originally , this film was xxup not a box office hit , but in light of recent xxmaj hollywood releases ( most of which have been decidedly formula - ridden , plot less , pointless , " save - the - blonde - chick - no - matter - what " xxunk ) , xxmaj xxunk of xxmaj all xxmaj xxunk , certainly in this sorry context deserves a second opinion . xxmaj the film -- like the book -- loses xxunk in some of the historical background , but it xxunk a uniquely xxmaj american dilemma set against the uniquely horrific xxmaj american xxunk of human xxunk , and some of its tragic ( and funny , and touching ) consequences . 

 xxmaj and worthy of xxunk out is the youthful xxmaj robert xxmaj xxunk , cast as the leading figure , xxmaj xxunk , whose xxunk xxunk is truly universal as he sets out in the beginning of his ' coming of age , ' only to be xxunk disappointed at what turns out to become his true education in the ways of the xxmaj southern plantation world of xxmaj xxunk , at the xxunk of the xxunk period . xxmaj when i saw the previews featuring the ( xxunk ) blond - xxunk xxmaj xxunk , i expected a xxunk , a xxunk , a xxunk -- i was pleasantly surprised . 

 xxmaj xxunk xxmaj davis , xxmaj ruby xxmaj dee , the late xxmaj ben xxmaj xxunk , xxmaj xxunk xxmaj xxunk , xxmaj victoria xxmaj xxunk and even xxmaj xxunk xxmaj guy xxunk vivid imagery and formidable skill as actors in the backdrop xxunk of xxunk , voodoo , xxmaj xxunk " xxunk , " and xxmaj xxunk revolt woven into this tale of human passion , hate , love , family , and racial xxunk in a society which is supposedly gone and yet somehow is still with us .

But the underlying data is all numbers

data.train_ds[0][0].data[:10]
array([   2,   18,  146,   19, 3788,   10,   20,   31,   25,    5])

With the data block API

如何用TextList.from_csv构建DataBunch

如何用TextList.from_csv构建DataBunch

We can use the data block API with NLP and have a lot more flexibility than what the default factory methods offer. In the previous example for instance, the data was randomly split between train and validation instead of reading the third column of the csv.

With the data block API though, we have to manually call the tokenize and numericalize steps. This allows more flexibility, and if you’re not using the defaults from fastai, the variaous arguments to pass will appear in the step they’re revelant, so it’ll be more readable.

data = (TextList.from_csv(path, 'texts.csv', cols='text')
                .split_from_df(col=2)
                .label_from_df(cols=0)
                .databunch())

Language model

如果数据量过大,需要调小批量

如果数据量过大,需要调小批量

Note that language models can use a lot of GPU, so you may need to decrease batchsize here.

bs=48
下载完整数据并查看文件夹

下载完整数据并查看文件夹

Now let’s grab the full dataset for what follows.

path = untar_data(URLs.IMDB)
path.ls()
[PosixPath('/home/ubuntu/.fastai/data/imdb/test'),
 PosixPath('/home/ubuntu/.fastai/data/imdb/tmp_clas'),
 PosixPath('/home/ubuntu/.fastai/data/imdb/README'),
 PosixPath('/home/ubuntu/.fastai/data/imdb/unsup'),
 PosixPath('/home/ubuntu/.fastai/data/imdb/train'),
 PosixPath('/home/ubuntu/.fastai/data/imdb/tmp_lm'),
 PosixPath('/home/ubuntu/.fastai/data/imdb/models'),
 PosixPath('/home/ubuntu/.fastai/data/imdb/imdb.vocab')]
(path/'train').ls()
[PosixPath('/home/ubuntu/.fastai/data/imdb/train/neg'),
 PosixPath('/home/ubuntu/.fastai/data/imdb/train/unsupBow.feat'),
 PosixPath('/home/ubuntu/.fastai/data/imdb/train/pos'),
 PosixPath('/home/ubuntu/.fastai/data/imdb/train/labeledBow.feat')]
如何做NLP的迁移学习

如何做NLP的迁移学习

The reviews are in a training and test set following an imagenet structure. The only difference is that there is an unsup folder on top of train and test that contains the unlabelled data.

We’re not going to train a model that classifies the reviews from scratch. Like in computer vision, we’ll use a model pretrained on a bigger dataset (a cleaned subset of wikipedia called wikitext-103). That model has been trained to guess what the next word, its input being all the previous words. It has a recurrent structure and a hidden state that is updated each time it sees a new word. This hidden state thus contains information about the sentence up to that point.

We are going to use that ‘knowledge’ of the English language to build our classifier, but first, like for computer vision, we need to fine-tune the pretrained model to our particular dataset. Because the English of the reviews left by people on IMDB isn’t the same as the English of wikipedia, we’ll need to adjust the parameters of our model by a little bit. Plus there might be some words that would be extremely common in the reviews dataset but would be barely present in wikipedia, and therefore might not be part of the vocabulary the model was trained on.

如何将三个文件夹数据汇集成训练数据,并生成TextDataBunch

如何将三个文件夹数据汇集成训练数据,并生成TextDataBunch

This is where the unlabelled data is going to be useful to us, as we can use it to fine-tune our model. Let’s create our data object with the data block API (next line takes a few minutes).

data_lm = (TextList.from_folder(path)
           #Inputs: all the text files in path
            .filter_by_folder(include=['train', 'test', 'unsup']) 
           #We may have other temp folders that contain text files 
           # so we only keep what's in train and test
            .random_split_by_pct(0.1)
           #We randomly split and keep 10% (10,000 reviews) for validation
            .label_for_lm()           
           #We want to do a language model so we label accordingly
            .databunch(bs=bs))
data_lm.save('data_lm.pkl')
TextDataBunch:忽略label, shuffle训练集而非验证集

TextDataBunch:忽略label, shuffle训练集而非验证集

We have to use a special kind of TextDataBunch for the language model, that ignores the labels (that’s why we put 0 everywhere), will shuffle the texts at each epoch before concatenating them all together (only for training, we don’t shuffle for the validation set) and will send batches that read that text in order with targets that are the next word in the sentence.

The line before being a bit long, we want to load quickly the final ids by using the following cell.

data_lm = load_data(path, 'data_lm.pkl', bs=bs)
data_lm.show_batch()
idx text
0 original script that xxmaj david xxmaj dhawan has worked on . xxmaj this one was a complete bit y bit rip off xxmaj hitch . i have nothing against remakes as such , but this one is just so lousy that it makes you even hate the original one ( which was pretty decent ) . i fail to understand what actors like xxmaj salman and xxmaj govinda saw in
1 ' classic ' xxmaj the xxmaj big xxmaj doll xxmaj house ' , which takes xxmaj awful to a whole new level . i can heartily recommend these two xxunk as a double - bill . xxmaj you 'll laugh yourself silly . xxbos xxmaj this movie is a pure disaster , the story is stupid and the editing is the worst i have seen , it confuses you incredibly
2 of xxmaj european cinema 's most quietly disturbing sociopaths and one of the most memorable finales of all time ( shamelessly stolen by xxmaj tarantino for xxmaj kill xxmaj bill xxmaj volume xxmaj two ) , but it has plenty more to offer than that . xxmaj playing around with chronology and inverting the usual clichés of standard ' lady vanishes ' plots , it also offers superb characterisation and
3 but even xxmaj martin xxmaj short managed a distinct , supporting character . ) \n\n i can understand the attraction of an imaginary world created in a good romantic comedy . xxmaj but this film is the prozac version of an imaginary world . i 'm frightened to consider that anyone could enjoy it even as pure fantasy . xxbos movie i have ever seen . xxmaj actually i find
4 xxmaj pre - xxmaj code film . xxbos xxmaj here 's a decidedly average xxmaj italian post apocalyptic take on the hunting / killing humans for sport theme ala xxmaj the xxmaj most xxmaj dangerous xxmaj game , xxmaj turkey xxmaj shoot , xxmaj gymkata and xxmaj the xxmaj running xxmaj man . \n\n xxmaj certainly the film reviewed here is nowhere near as much fun as the other listed
基于NLP构建迁移学习模型

基于NLP构建迁移学习模型

We can then put this in a learner object very easily with a model loaded with the pretrained weights. They’ll be downloaded the first time you’ll execute the following line and stored in ~/.fastai/models/ (or elsewhere if you specified different paths in your config file).

learn = language_model_learner(data_lm, AWD_LSTM, drop_mult=0.3)
寻找最优学习率并画图

寻找最优学习率并画图

learn.lr_find()
LR Finder is complete, type {learner_name}.recorder.plot() to see the graph.
learn.recorder.plot(skip_end=15)

output_66_0

设置momentum来训练

设置momentum来训练

learn.fit_one_cycle(1, 1e-2, moms=(0.8,0.7))
learn.save('fit_head')
加载模型,解冻,调节学习率继续训练

加载模型,解冻,调节学习率继续训练

learn.load('fit_head');

To complete the fine-tuning, we can then unfeeze and launch a new training.

learn.unfreeze()
learn.fit_one_cycle(10, 1e-3, moms=(0.8,0.7))
learn.save('fine_tuned')
验证模型效果

验证模型效果

How good is our model? Well let’s try to see what it predicts after a few given words.

learn.load('fine_tuned');
TEXT = "I liked this movie because"
N_WORDS = 40
N_SENTENCES = 2
print("\n".join(learn.predict(TEXT, N_WORDS, temperature=0.75) for _ in range(N_SENTENCES)))
I liked this movie because of the cool scenery and the high level of xxmaj british hunting . xxmaj the only thing this movie has going for it is the horrible acting and no script . xxmaj the movie was a big disappointment . xxmaj
I liked this movie because it was one of the few movies that made me laugh so hard i did n't like it . xxmaj it was a hilarious film and it was very entertaining . 

 xxmaj the acting was great , i 'm
保存encoder

保存encoder

We not only have to save the model, but also it’s encoder, the part that’s responsible for creating and updating the hidden state. For the next part, we don’t care about the part that tries to guess the next word.

learn.save_encoder('fine_tuned_enc')

Classifier

下载数据

下载数据

Now, we’ll create a new data object that only grabs the labelled data and keeps those labels. Again, this line takes a bit of time.

path = untar_data(URLs.IMDB)
生成Databunch并保存

生成Databunch并保存

data_clas = (TextList.from_folder(path, vocab=data_lm.vocab)
             #grab all the text files in path
             .split_by_folder(valid='test')
             #split by train and valid folder 
             # (that only keeps 'train' and 'test' so no need to filter)
             .label_from_folder(classes=['neg', 'pos'])
             #label them all with their folders
             .databunch(bs=bs))

data_clas.save('data_clas.pkl')
加载并展示数据

加载并展示数据

data_clas = load_data(path, 'data_clas.pkl', bs=bs)
data_clas.show_batch()
text target
xxbos xxmaj match 1 : xxmaj tag xxmaj team xxmaj table xxmaj match xxmaj bubba xxmaj ray and xxmaj spike xxmaj dudley vs xxmaj eddie xxmaj guerrero and xxmaj chris xxmaj benoit xxmaj bubba xxmaj ray and xxmaj spike xxmaj dudley started things off with a xxmaj tag xxmaj team xxmaj table xxmaj match against xxmaj eddie xxmaj guerrero and xxmaj chris xxmaj benoit . xxmaj according to the rules pos
xxbos xxmaj titanic directed by xxmaj james xxmaj cameron presents a fictional love story on the historical setting of the xxmaj titanic . xxmaj the plot is simple , xxunk , or not for those who love plots that twist and turn and keep you in suspense . xxmaj the end of the movie can be figured out within minutes of the start of the film , but the love pos
xxbos xxmaj here are the matches . . . ( adv . = advantage ) \n\n xxmaj the xxmaj warriors ( xxmaj ultimate xxmaj warrior , xxmaj texas xxmaj tornado and xxmaj legion of xxmaj doom ) v xxmaj the xxmaj perfect xxmaj team ( xxmaj mr xxmaj perfect , xxmaj ax , xxmaj smash and xxmaj crush of xxmaj demolition ) : xxmaj ax is the first to go neg
xxbos i felt duty bound to watch the 1983 xxmaj timothy xxmaj dalton / xxmaj zelah xxmaj clarke adaptation of " xxmaj jane xxmaj eyre , " because i 'd just written an article about the 2006 xxup bbc " xxmaj jane xxmaj eyre " for xxunk . \n\n xxmaj so , i approached watching this the way i 'd approach doing homework . \n\n i was irritated at first pos
xxbos xxmaj no , this is n't a sequel to the fabulous xxup ova series , but rather a remake of the events that occurred after the death of xxmaj xxunk ( and the disappearance of xxmaj woodchuck ) . xxmaj it is also more accurate to the novels that inspired this wonderful series , which is why characters ( namely xxmaj orson and xxmaj xxunk ) are xxunk , pos
用迁移学习构建一个语言分类器

用迁移学习构建一个语言分类器

We can then create a model to classify those reviews and load the encoder we saved before.

learn = text_classifier_learner(data_clas, AWD_LSTM, drop_mult=0.5)
learn.load_encoder('fine_tuned_enc')
寻找最优学习率并作图

寻找最优学习率并作图

learn.lr_find()
learn.recorder.plot()
用momentum帮助训练

用momentum帮助训练

learn.fit_one_cycle(1, 2e-2, moms=(0.8,0.7))
learn.save('first')
加载模型,解冻,训练(slice, moms), 保存模型

加载模型,解冻,训练(slice, moms), 保存模型

learn.load('first');
learn.freeze_to(-2)
learn.fit_one_cycle(1, slice(1e-2/(2.6**4),1e-2), moms=(0.8,0.7))
learn.save('second')
加载模型,冰冻至倒数第三层,再训练

加载模型,冰冻至倒数第三层,再训练

learn.load('second');
learn.freeze_to(-3)
learn.fit_one_cycle(1, slice(5e-3/(2.6**4),5e-3), moms=(0.8,0.7))
learn.save('third')
加载模型,解冻,训练2次(slice,moms)

加载模型,解冻,训练2次(slice,moms)

learn.load('third');
learn.unfreeze()
learn.fit_one_cycle(2, slice(1e-3/(2.6**4),1e-3), moms=(0.8,0.7))
预测

预测

learn.predict("I really loved that movie, it was awesome!")
(Category pos, tensor(1), tensor([7.5928e-04, 9.9924e-01]))

Multi-label prediction with Planet Amazon dataset

三行魔法代码

三行魔法代码

%reload_ext autoreload
%autoreload 2
%matplotlib inline
所需library

所需library

from fastai.vision import *

Getting the data

如何从Kaggle下载数据

如何从Kaggle下载数据

The planet dataset isn’t available on the fastai dataset page due to copyright restrictions. You can download it from Kaggle however. Let’s see how to do this by using the Kaggle API as it’s going to be pretty useful to you if you want to join a competition or use other Kaggle datasets later on.

First, install the Kaggle API by uncommenting the following line and executing it, or by executing it in your terminal (depending on your platform you may need to modify this slightly to either add source activate fastai or similar, or prefix pip with a path. Have a look at how conda install is called for your platform in the appropriate Returning to work section of https://course.fast.ai/. (Depending on your environment, you may also need to append “–user” to the command.)

# ! pip install kaggle --upgrade

Then you need to upload your credentials from Kaggle on your instance. Login to kaggle and click on your profile picture on the top left corner, then ‘My account’. Scroll down until you find a button named ‘Create New API Token’ and click on it. This will trigger the download of a file named ‘kaggle.json’.

Upload this file to the directory this notebook is running in, by clicking “Upload” on your main Jupyter page, then uncomment and execute the next two commands (or run them in a terminal). For Windows, uncomment the last two commands.

# ! mkdir -p ~/.kaggle/
# ! mv kaggle.json ~/.kaggle/

# For Windows, uncomment these two commands
# ! mkdir %userprofile%\.kaggle
# ! move kaggle.json %userprofile%\.kaggle

You’re all set to download the data from planet competition. You first need to go to its main page and accept its rules, and run the two cells below (uncomment the shell commands to download and unzip the data). If you get a 403 forbidden error it means you haven’t accepted the competition rules yet (you have to go to the competition page, click on Rules tab, and then scroll to the bottom to find the accept button).

path = Config.data_path()/'planet'
path.mkdir(parents=True, exist_ok=True)
path
PosixPath('/home/ubuntu/.fastai/data/planet')
# ! kaggle competitions download -c planet-understanding-the-amazon-from-space -f train-jpg.tar.7z -p {path}  
# ! kaggle competitions download -c planet-understanding-the-amazon-from-space -f train_v2.csv -p {path}  
# ! unzip -q -n {path}/train_v2.csv.zip -d {path}

To extract the content of this file, we’ll need 7zip, so uncomment the following line if you need to install it (or run sudo apt install p7zip-full in your terminal).

# ! conda install -y -c haasad eidl7zip

And now we can unpack the data (uncomment to run - this might take a few minutes to complete).

# ! 7za -bd -y -so x {path}/train-jpg.tar.7z | tar xf - -C {path.as_posix()}

Multiclassification

查看CSV,一图多标注

查看CSV,一图多标注

Contrary to the pets dataset studied in last lesson, here each picture can have multiple labels. If we take a look at the csv file containing the labels (in ‘train_v2.csv’ here) we see that each ‘image_name’ is associated to several tags separated by spaces.

df = pd.read_csv(path/'train_v2.csv')
df.head()
.dataframe tbody tr th:only-of-type { vertical-align: middle; }
.dataframe tbody tr th {
    vertical-align: top;
}

.dataframe thead th {
    text-align: right;
}
image_name tags
0 train_0 haze primary
1 train_1 agriculture clear primary water
2 train_2 clear primary
3 train_3 clear primary
4 train_4 agriculture clear habitation primary road
为什么用ImageList而非ImageDataBunch

为什么用ImageList而非ImageDataBunch

To put this in a DataBunch while using the data block API, we then need to using ImageList (and not ImageDataBunch). This will make sure the model created has the proper loss function to deal with the multiple classes.

设置变形细节

设置变形细节

tfms = get_transforms(flip_vert=True, max_lighting=0.1, max_zoom=1.05, max_warp=0.)

We use parentheses around the data block pipeline below, so that we can use a multiline statement without needing to add ‘\’.

用ImageList构建数据src,然后再建DataBunch

用ImageList构建数据src,然后再建DataBunch

np.random.seed(42)
src = (ImageList.from_csv(path, 'train_v2.csv', folder='train-jpg', suffix='.jpg')
       .random_split_by_pct(0.2)
       .label_from_df(label_delim=' '))
data = (src.transform(tfms, size=128)
        .databunch().normalize(imagenet_stats))
查看数据

查看数据

show_batch still works, and show us the different labels separated by ;.

data.show_batch(rows=3, figsize=(12,9))

如何设计thresh_accuracy

如何设计thresh_accuracy

To create a Learner we use the same function as in lesson 1. Our base architecture is resnet34 again, but the metrics are a little bit differeent: we use accuracy_thresh instead of accuracy. In lesson 1, we determined the predicition for a given class by picking the final activation that was the biggest, but here, each activation can be 0. or 1. accuracy_thresh selects the ones that are above a certain threshold (0.5 by default) and compares them to the ground truth.

As for Fbeta, it’s the metric that was used by Kaggle on this competition. See here for more details.

挑选模型结构

挑选模型结构

arch = models.resnet50
设计含threshold的accuracy和F-score

设计含threshold的accuracy和F-score

acc_02 = partial(accuracy_thresh, thresh=0.2)
f_score = partial(fbeta, thresh=0.2)
构建模型

构建模型

learn = create_cnn(data, arch, metrics=[acc_02, f_score])
Downloading: "https://download.pytorch.org/models/resnet50-19c8e357.pth" to /home/ubuntu/.torch/models/resnet50-19c8e357.pth
100%|██████████| 102502400/102502400 [00:01<00:00, 100859665.66it/s]
寻找学习率,作图,挑选最优值

寻找学习率,作图,挑选最优值

We use the LR Finder to pick a good learning rate.

learn.lr_find()
LR Finder is complete, type {learner_name}.recorder.plot() to see the graph.
learn.recorder.plot()

output_45_0

Then we can fit the head of our network.

lr = 0.01
训练模型

训练模型

learn.fit_one_cycle(5, slice(lr))
learn.save('stage-1-rn50')
解冻,再次寻找学习率,再训练

解冻,再次寻找学习率,再训练

…And fine-tune the whole model:

learn.unfreeze()
learn.lr_find()
learn.recorder.plot()
LR Finder complete, type {learner_name}.recorder.plot() to see the graph.

output_54_1

learn.fit_one_cycle(5, slice(1e-5, lr/5))

Total time: 04:00

epoch train_loss valid_loss accuracy_thresh fbeta
1 0.097016 0.094868 0.952004 0.916215
2 0.095774 0.088899 0.954540 0.922340
3 0.090646 0.085958 0.959249 0.924921
4 0.085097 0.083291 0.958849 0.928195
5 0.079197 0.082855 0.958602 0.928259
learn.save('stage-2-rn50')
放大图片,生成新的Databunch

放大图片,生成新的Databunch

data = (src.transform(tfms, size=256)
        .databunch().normalize(imagenet_stats))

learn.data = data
data.train_ds[0][0].shape
torch.Size([3, 256, 256])
封冻模型,只训练最后一层

封冻模型,只训练最后一层

learn.freeze()
寻找学习率,作图,选择最优值

寻找学习率,作图,选择最优值

learn.lr_find()
learn.recorder.plot()
LR Finder complete, type {learner_name}.recorder.plot() to see the graph.

output_62_1

lr=1e-2/2
训练,保存

训练,保存

learn.fit_one_cycle(5, slice(lr))

Total time: 09:01

epoch train_loss valid_loss accuracy_thresh fbeta
1 0.087761 0.085013 0.958006 0.926066
2 0.087641 0.083732 0.958260 0.927459
3 0.084250 0.082856 0.958485 0.928200
4 0.082347 0.081470 0.960091 0.929166
5 0.078463 0.080984 0.959249 0.930089
learn.save('stage-1-256-rn50')
解冻,调节学习效率,再训练

解冻,调节学习效率,再训练

learn.unfreeze()
learn.fit_one_cycle(5, slice(1e-5, lr/5))

Total time: 11:25

epoch train_loss valid_loss accuracy_thresh fbeta
1 0.082938 0.083548 0.957846 0.927756
2 0.086312 0.084802 0.958718 0.925416
3 0.084824 0.082339 0.959975 0.930054
4 0.078784 0.081425 0.959983 0.929634
5 0.074530 0.080791 0.960426 0.931257
画出训练中的损失值变化图

画出训练中的损失值变化图

learn.recorder.plot_losses()

output_71_0

learn.save('stage-2-256-rn50')

Finish

生成预测值,上传Kaggle

生成预测值,上传Kaggle

You won’t really know how you’re going until you submit to Kaggle, since the leaderboard isn’t using the same subset as we have for training. But as a guide, 50th place (out of 938 teams) on the private leaderboard was a score of 0.930.

learn.export()

(This section will be covered in part 2 - please don’t ask about it just yet! :slight_smile: )

#! kaggle competitions download -c planet-understanding-the-amazon-from-space -f test-jpg.tar.7z -p {path}  
#! 7za -bd -y -so x {path}/test-jpg.tar.7z | tar xf - -C {path}
#! kaggle competitions download -c planet-understanding-the-amazon-from-space -f test-jpg-additional.tar.7z -p {path}  
#! 7za -bd -y -so x {path}/test-jpg-additional.tar.7z | tar xf - -C {path}
test = ImageList.from_folder(path/'test-jpg').add(ImageList.from_folder(path/'test-jpg-additional'))
len(test)
61191
learn = load_learner(path, test=test)
preds, _ = learn.get_preds(ds_type=DatasetType.Test)
thresh = 0.2
labelled_preds = [' '.join([learn.data.classes[i] for i,p in enumerate(pred) if p > thresh]) for pred in preds]
labelled_preds[:5]
['agriculture cultivation partly_cloudy primary road',
 'clear haze primary water',
 'agriculture clear cultivation primary',
 'clear primary',
 'partly_cloudy primary']
fnames = [f.name[:-4] for f in learn.data.test_ds.items]
df = pd.DataFrame({'image_name':fnames, 'tags':labelled_preds}, columns=['image_name', 'tags'])
df.to_csv(path/'submission.csv', index=False)
! kaggle competitions submit planet-understanding-the-amazon-from-space -f {path/'submission.csv'} -m "My submission"
Warning: Your Kaggle API key is readable by other users on this system! To fix this, you can run 'chmod 600 /home/ubuntu/.kaggle/kaggle.json'
100%|██████████████████████████████████████| 2.18M/2.18M [00:02<00:00, 1.05MB/s]
Successfully submitted to Planet: Understanding the Amazon from Space

Private Leaderboard score: 0.9296 (around 80th)

Collaborative Filtering on Movie Lens

所需library

所需library

from fastai.collab import *
from fastai.tabular import *

Collaborative filtering example

核心数据名称

核心数据名称

collab models use data in a DataFrame of user, items, and ratings.

user,item,title = 'userId','movieId','title'
下载数据

下载数据

path = untar_data(URLs.ML_SAMPLE)
path
PosixPath('/home/ubuntu/.fastai/data/movie_lens_sample')
查看CSV

查看CSV

ratings = pd.read_csv(path/'ratings.csv')
ratings.head()
.dataframe tbody tr th:only-of-type { vertical-align: middle; }
.dataframe tbody tr th {
    vertical-align: top;
}

.dataframe thead th {
    text-align: right;
}
userId movieId rating timestamp
0 73 1097 4.0 1255504951
1 561 924 3.5 1172695223
2 157 260 3.5 1291598691
3 358 1210 5.0 957481884
4 130 316 2.0 1138999234
生成CollabDataBunch

生成CollabDataBunch

That’s all we need to create and train a model:

data = CollabDataBunch.from_df(ratings, seed=42)
设置y的区间,创建collab learner

设置y的区间,创建collab learner

y_range = [0,5.5]
learn = collab_learner(data, n_factors=50, y_range=y_range)
用lr=5e-3训练

用lr=5e-3训练

learn.fit_one_cycle(3, 5e-3)

Total time: 00:03

epoch train_loss valid_loss
1 1.629454 0.982241
2 0.856353 0.678751
3 0.655987 0.669647

Movielens 100k

下载完整Movielens 100k数据集

下载完整Movielens 100k数据集

Let’s try with the full Movielens 100k data dataset, available from http://files.grouplens.org/datasets/movielens/ml-100k.zip

调取数据,查看CSV

调取数据,查看CSV

path=Config.data_path()/'ml-100k'
调取rating数据

调取rating数据

ratings = pd.read_csv(path/'u.data', delimiter='\t', header=None,
                      names=[user,item,'rating','timestamp'])
ratings.head()
.dataframe tbody tr th:only-of-type { vertical-align: middle; }
.dataframe tbody tr th {
    vertical-align: top;
}

.dataframe thead th {
    text-align: right;
}
userId movieId rating timestamp
0 196 242 3 881250949
1 186 302 3 891717742
2 22 377 1 878887116
3 244 51 2 880606923
4 166 346 1 886397596
调取电影数据

调取电影数据

movies = pd.read_csv(path/'u.item',  delimiter='|', encoding='latin-1', header=None,
                    names=[item, 'title', 'date', 'N', 'url', *[f'g{i}' for i in range(19)]])
movies.head()
.dataframe tbody tr th:only-of-type { vertical-align: middle; }
.dataframe tbody tr th {
    vertical-align: top;
}

.dataframe thead th {
    text-align: right;
}
movieId title date N url g0 g1 g2 g3 g4 ... g9 g10 g11 g12 g13 g14 g15 g16 g17 g18
0 1 Toy Story (1995) 01-Jan-1995 NaN http://us.imdb.com/M/title-exact?Toy%20Story%2... 0 0 0 1 1 ... 0 0 0 0 0 0 0 0 0 0
1 2 GoldenEye (1995) 01-Jan-1995 NaN http://us.imdb.com/M/title-exact?GoldenEye%20(... 0 1 1 0 0 ... 0 0 0 0 0 0 0 1 0 0
2 3 Four Rooms (1995) 01-Jan-1995 NaN http://us.imdb.com/M/title-exact?Four%20Rooms%... 0 0 0 0 0 ... 0 0 0 0 0 0 0 1 0 0
3 4 Get Shorty (1995) 01-Jan-1995 NaN http://us.imdb.com/M/title-exact?Get%20Shorty%... 0 1 0 0 0 ... 0 0 0 0 0 0 0 0 0 0
4 5 Copycat (1995) 01-Jan-1995 NaN http://us.imdb.com/M/title-exact?Copycat%20(1995) 0 0 0 0 0 ... 0 0 0 0 0 0 0 1 0 0

5 rows × 24 columns

len(ratings)
100000
将rating和电影数据合并

将rating和电影数据合并

rating_movie = ratings.merge(movies[[item, title]])
rating_movie.head()
.dataframe tbody tr th:only-of-type { vertical-align: middle; }
.dataframe tbody tr th {
    vertical-align: top;
}

.dataframe thead th {
    text-align: right;
}
userId movieId rating timestamp title
0 196 242 3 881250949 Kolya (1996)
1 63 242 3 875747190 Kolya (1996)
2 226 242 5 883888671 Kolya (1996)
3 154 242 3 879138235 Kolya (1996)
4 306 242 5 876503793 Kolya (1996)
从合并的df中创建CollabDataBunch

从合并的df中创建CollabDataBunch

data = CollabDataBunch.from_df(rating_movie, seed=42, valid_pct=0.1, item_name=title)
data.show_batch()
userId title target
126 Event Horizon (1997) 1.0
44 Young Frankenstein (1974) 4.0
718 Star Trek: First Contact (1996) 4.0
506 Magnificent Seven, The (1954) 5.0
373 Good, The Bad and The Ugly, The (1966) 3.0
构建collab_learner

构建collab_learner

y_range = [0,5.5]
learn = collab_learner(data, n_factors=40, y_range=y_range, wd=1e-1)
寻找学习率,作图,选择最优值

寻找学习率,作图,选择最优值

learn.lr_find()
learn.recorder.plot(skip_end=15)
LR Finder is complete, type {learner_name}.recorder.plot() to see the graph.

output_38_1

训练,保存

训练,保存

learn.fit_one_cycle(5, 5e-3)

Total time: 00:30

epoch train_loss valid_loss
1 0.923900 0.946068
2 0.865458 0.890646
3 0.783896 0.836753
4 0.638374 0.815428
5 0.561979 0.814652
learn.save('dotprod')

Here’s some benchmarks on the same dataset for the popular Librec system for collaborative filtering. They show best results based on RMSE of 0.91, which corresponds to an MSE of 0.91**2 = 0.83.

Interpretation 解读模型效果

加载模型

加载模型

learn.load('dotprod');
learn.model
EmbeddingDotBias(
  (u_weight): Embedding(944, 40)
  (i_weight): Embedding(1654, 40)
  (u_bias): Embedding(944, 1)
  (i_bias): Embedding(1654, 1)
)
获取每部影片的点评数量

获取每部影片的点评数量

g = rating_movie.groupby(title)['rating'].count()
从多到少排列前1000部电影,展示最高的10部

从多到少排列前1000部电影,展示最高的10部

top_movies = g.sort_values(ascending=False).index.values[:1000]
top_movies[:10]
array(['Star Wars (1977)', 'Contact (1997)', 'Fargo (1996)', 'Return of the Jedi (1983)', 'Liar Liar (1997)',
       'English Patient, The (1996)', 'Scream (1996)', 'Toy Story (1995)', 'Air Force One (1997)',
       'Independence Day (ID4) (1996)'], dtype=object)

Movie bias

如何获取movie bias

如何获取movie bias

movie_bias = learn.bias(top_movies, is_item=True)
movie_bias.shape
torch.Size([1000])
对每部电影评分取均值

对每部电影评分取均值

mean_ratings = rating_movie.groupby(title)['rating'].mean()
将movie_bias, title, 和评分均值排在一起

将movie_bias, title, 和评分均值排在一起

movie_ratings = [(b, i, mean_ratings.loc[i]) for i,b in zip(top_movies,movie_bias)]
将电影按movie_bias高低排列,从高到低,从低到高

将电影按movie_bias高低排列,从高到低,从低到高

item0 = lambda o:o[0]
sorted(movie_ratings, key=item0)[:15]
[(tensor(-0.3667),
  'Children of the Corn: The Gathering (1996)',
  1.3157894736842106),
 (tensor(-0.3142),
  'Lawnmower Man 2: Beyond Cyberspace (1996)',
  1.7142857142857142),
 (tensor(-0.2926), 'Mortal Kombat: Annihilation (1997)', 1.9534883720930232),
 (tensor(-0.2708), 'Cable Guy, The (1996)', 2.339622641509434),
 (tensor(-0.2669), 'Striptease (1996)', 2.2388059701492535),
 (tensor(-0.2641), 'Free Willy 3: The Rescue (1997)', 1.7407407407407407),
 (tensor(-0.2511), 'Beautician and the Beast, The (1997)', 2.313953488372093),
 (tensor(-0.2418), 'Bio-Dome (1996)', 1.903225806451613),
 (tensor(-0.2345), "Joe's Apartment (1996)", 2.2444444444444445),
 (tensor(-0.2324), 'Island of Dr. Moreau, The (1996)', 2.1578947368421053),
 (tensor(-0.2266), 'Barb Wire (1996)', 1.9333333333333333),
 (tensor(-0.2219), 'Crow: City of Angels, The (1996)', 1.9487179487179487),
 (tensor(-0.2208), 'Grease 2 (1982)', 2.0),
 (tensor(-0.2151), 'Home Alone 3 (1997)', 1.894736842105263),
 (tensor(-0.2089), "McHale's Navy (1997)", 2.1884057971014492)]
sorted(movie_ratings, key=lambda o: o[0], reverse=True)[:15]
[(tensor(0.5913), "Schindler's List (1993)", 4.466442953020135),
 (tensor(0.5700), 'Titanic (1997)', 4.2457142857142856),
 (tensor(0.5623), 'Shawshank Redemption, The (1994)', 4.445229681978798),
 (tensor(0.5412), 'L.A. Confidential (1997)', 4.161616161616162),
 (tensor(0.5368), 'Rear Window (1954)', 4.3875598086124405),
 (tensor(0.5193), 'Star Wars (1977)', 4.3584905660377355),
 (tensor(0.5149), 'As Good As It Gets (1997)', 4.196428571428571),
 (tensor(0.5114), 'Silence of the Lambs, The (1991)', 4.28974358974359),
 (tensor(0.5097), 'Good Will Hunting (1997)', 4.262626262626263),
 (tensor(0.4946), 'Vertigo (1958)', 4.251396648044692),
 (tensor(0.4899), 'Godfather, The (1972)', 4.283292978208232),
 (tensor(0.4855), 'Boot, Das (1981)', 4.203980099502488),
 (tensor(0.4769), 'Usual Suspects, The (1995)', 4.385767790262173),
 (tensor(0.4743), 'Casablanca (1942)', 4.45679012345679),
 (tensor(0.4665), 'Close Shave, A (1995)', 4.491071428571429)]

Movie weights

获取电影权重参数

获取电影权重参数

movie_w = learn.weight(top_movies, is_item=True)
movie_w.shape
torch.Size([1000, 40])
对电影参数matrix取PCA前3个特征值

对电影参数matrix取PCA前3个特征值

movie_pca = movie_w.pca(3)
movie_pca.shape
torch.Size([1000, 3])
将每部电影和它的第一特征值排在一起

将每部电影和它的第一特征值排在一起

fac0,fac1,fac2 = movie_pca.t()
movie_comp = [(f, i) for f,i in zip(fac0, top_movies)]
按第一特征值高低排序,从高到低,从低到高

按第一特征值高低排序,从高到低,从低到高

sorted(movie_comp, key=itemgetter(0), reverse=True)[:10]
[(tensor(1.2412), 'Home Alone 3 (1997)'),
 (tensor(1.2072), 'Jungle2Jungle (1997)'),
 (tensor(1.2000), 'Bio-Dome (1996)'),
 (tensor(1.1883), 'Leave It to Beaver (1997)'),
 (tensor(1.1570), 'Children of the Corn: The Gathering (1996)'),
 (tensor(1.1309), "McHale's Navy (1997)"),
 (tensor(1.1187), 'D3: The Mighty Ducks (1996)'),
 (tensor(1.0956), 'Congo (1995)'),
 (tensor(1.0950), 'Free Willy 3: The Rescue (1997)'),
 (tensor(1.0524), 'Cutthroat Island (1995)')]
sorted(movie_comp, key=itemgetter(0))[:10]
[(tensor(-1.0692), 'Casablanca (1942)'),
 (tensor(-1.0523), 'Close Shave, A (1995)'),
 (tensor(-1.0142), 'When We Were Kings (1996)'),
 (tensor(-1.0075), 'Lawrence of Arabia (1962)'),
 (tensor(-1.0034), 'Wrong Trousers, The (1993)'),
 (tensor(-0.9905), 'Chinatown (1974)'),
 (tensor(-0.9692), 'Ran (1985)'),
 (tensor(-0.9541), 'Apocalypse Now (1979)'),
 (tensor(-0.9523), 'Wallace & Gromit: The Best of Aardman Animation (1996)'),
 (tensor(-0.9369), 'Some Folks Call It a Sling Blade (1993)')]
同样方法,套用第二特征

同样方法,套用第二特征

movie_comp = [(f, i) for f,i in zip(fac1, top_movies)]
sorted(movie_comp, key=itemgetter(0), reverse=True)[:10]
[(tensor(0.8788), 'Ready to Wear (Pret-A-Porter) (1994)'),
 (tensor(0.8263), 'Keys to Tulsa (1997)'),
 (tensor(0.8066), 'Nosferatu (Nosferatu, eine Symphonie des Grauens) (1922)'),
 (tensor(0.7730), 'Dead Man (1995)'),
 (tensor(0.7513), 'Three Colors: Blue (1993)'),
 (tensor(0.7492), 'Trainspotting (1996)'),
 (tensor(0.7414), 'Cable Guy, The (1996)'),
 (tensor(0.7330), 'Jude (1996)'),
 (tensor(0.7246), 'Clockwork Orange, A (1971)'),
 (tensor(0.7195), 'Stupids, The (1996)')]
sorted(movie_comp, key=itemgetter(0))[:10]
[(tensor(-1.2148), 'Braveheart (1995)'),
 (tensor(-1.1153), 'Titanic (1997)'),
 (tensor(-1.1148), 'Raiders of the Lost Ark (1981)'),
 (tensor(-0.8795), "It's a Wonderful Life (1946)"),
 (tensor(-0.8644), "Mr. Holland's Opus (1995)"),
 (tensor(-0.8619), 'Star Wars (1977)'),
 (tensor(-0.8558), 'Return of the Jedi (1983)'),
 (tensor(-0.8526), 'Pretty Woman (1990)'),
 (tensor(-0.8453), 'Independence Day (ID4) (1996)'),
 (tensor(-0.8450), 'Forrest Gump (1994)')]
根据第一第三特征值的高低,将电影在平面上排列出来

根据第一第三特征值的高低,将电影在平面上排列出来

idxs = np.random.choice(len(top_movies), 50, replace=False)
idxs = list(range(50))
X = fac0[idxs]
Y = fac2[idxs]
plt.figure(figsize=(15,15))
plt.scatter(X, Y)
for i, x, y in zip(top_movies[idxs], X, Y):
    plt.text(x,y,i, color=np.random.rand(3)*0.7, fontsize=11)
plt.show()

fastai part1 2019 中文版笔记视频的设想

为什么

- fast.ai是史上最务实最强大的深度学习课程
- 希望自己和更多国内小伙伴能因此受益
- 希望更多小伙伴参与到fast.ai深度学习的建设中来

是什么

- 课程知识点分解梳理+notebook 演示+中文讲解

目标

- 力争做到与英文课程内容高度一致和准确
- 作为精准贴切的中文字幕的另一种选择

效果

- 便捷搜索,方便复习的课程知识点集成

载体

- fast.ai 论坛, B站

难点

   - 现在和未来能用来做视频的时间非常少
   - 所以文字内容会多些,视频会留给特别内容和小伙伴邀请制作的内容。

Thank you for your translation. I would like to ask if there is a Chinese communication group (QQ group or WeChat group). Some questions are convenient for communication. Thank you, the author, bother.

fast.ai 见闻

搜集在fast.ai世界里看到的值得关注的动态和见闻

insights from fastai team

interviews with DL heros
interview with Sylvain by Sanyam Bhutani thanks to @init_27
I simply copied the following Q&As from @init_27 's post above

How Sylvain got started with fastai?

I kind of forgot about it (neural net) until October 2017… I was curious to see how the field had progressed — of course, I had heard all the hype around it — so I followed the MOOC version 1…I instantly loved the top-down approach… I have a strong background in Math, but it’s my love for coding practical things that kept me going.

What is it like to work with Jeremy Howard?

We never sleep, but that’s mostly because we both have toddlers!..I’ve improved a lot as a coder and I keep on learning new things from him. Just seeing how he iterates through your code to refactor it in a simpler or more elegant way is always fascinating. And I really love how he is never satisfied with anything short of perfect, always pushing to polish this bit of code or this particular API until it’s as easy to use as possible.

Could you tell us more about your role at fast.ai and how does a day at fast.ai look like?

Since I am based in New York City, we mostly work in parallel. We chat a lot on Skype to coordinate and the rest of the time is spent coding or reviewing code, whether it’s to make the library better or try a new research idea.

As for my role, it’s a mix of reviewing the latest papers and see what we could use, as well as help Jeremy develop new functionality in the library and prepare the next course.

What more can we expect next from the awesome library?

we’ll try to make it easier to put fastai models into production, we’ll focus on the applications we didn’t have time to finalize during the first part of the course (object detection, translation, sequence labeling), we’ll find some way to deal with very big datasets that don’t always fit in RAM, and also play with some research ideas we didn’t get to investigate (training on rectangular images for instance).

How do you discover these ideas, what is the methodology of experimentation at fast.ai?

The methodology could be summarized into: “try blah!”, as Jeremy said in one of the courses. We try to have an intuitive understanding of what happens when training a given model, then we experiment all the ideas we think of to see if they work empirically.

Very often, research papers focus on the Math first and come with this one new theory that is going to revolutionize everything. When you try to apply it though, you often don’t get any good results. We’re more interested in things that work in practice.

How do you stay up to date with the cutting edge?

By experimenting a lot! The fastai library isn’t just a great tool for the beginner, its high flexibility makes it super easy when I want to implement a research article to see if its suggestion results in a significant improvement. The callbacks system or the data block API allow you to do pretty much anything with just a few lines of code.

any advice for the beginners?

Start a blog, where you explain what you have learned. Explaining things is often the best way to realize you hadn’t fully understood them; you may discover there were tons of small details you hadn’t dug enough into.

中文社区动态
meetups

上海meetup征集中, 2019.3.4开始的,thanks to @royam0820 ,上海的小伙伴有福气啊!meetup提供微信群和slack供大家交流。

开启GPU使用心得

各种GPU server对比

fast.ai发展动态

未来swift将成为fast.ai的新宠,见详情
computational linear algebra course 简介
ML course in 2018 简介

可视化技巧

Jeremy 推荐可视化教程

时间序列与fastai

共享学习型竞赛, 时间序列学习小组, both thanks to @oguiza

技术应用

改变图片大小

竞赛分享
JN 技巧分享

thanks to @stas tips and tricks

文档建设

PR仅需四步
我的第一个PR
第一个PR:如何理解freeze to the last layer group?

1 Like

You are welcome! What you want may be found in 中文社区动态 of the post below。

欢迎使用Kaggle kernels!



Kaggle 是数据科学家和机器学习实践者的在线社区,隶属于谷歌公司。Kaggle 允许用户搜索和发布数据集,在网页环境中搭建和训练模型,与其他数据科学家和机器学习工程师在线合作,和参与竞赛解决数据科学问题。Kaggle 起源于提供竞赛,现在已成长为云端中数据科学实践的公开平台 ( 更多 ).

但是Kaggle Kernels 仍旧有其局限性,见资源与局限。如果你是重返kaggle, 直接前往你的Kernels,点击需要重返工作的kernel即可。

用 Kaggle kernels 来做 fast.ai v3 课程Notebook

Kaggle kernels 自带 fastai library, William Horton @wdhorton and Sanyam Bhutani @init_27 将课程 notebooks 输出到 Kaggle kernels上。Sanyam Bhutani 在维护这些 kernels, 相关问题可前往 discussion thread here.

没有任何设置安装要求,只需点击 “fork” 然后运行Notebook即可。

Kernels 目录

首次上手步骤

步骤 1: 创建Kaggle账户

注册Kaggle here,到邮件中确认。确认后,即可登陆账户。

步骤 2: 导航到相关Notebook (kernel)

点击上述任意课程Notebook链接,打开页面后,点击fork即可使用。

步骤 3: 一切就绪,直接上手!

我们以及设置好了课程所需的所有的数据集和前提要求,你可以像在本地环境中使用 jupyter notebook一样使用Kaggle kernel.

资源与局限

  • Kaggle kernels 是完全免费的
  • Notebook 不会像 fastai repository 一样频繁更新
  • 这些Notebooks 没有fast.ai 官方维护。 (Sanyam Bhutani 在坚持维护工作,相关链接 discussion thread )
  • GPU 时限 (K-80 instance) 每次是6小时。
  • 硬盘使用量 = 5 GB/kernel。
  • 内存用量 = 14 GB/kernel.

我的本地设置

如何不commit下,对Kaggle kernel大型文件下载 论坛分享

如何给你的code snippet做快捷键 论坛分享

如何做你的第一个文档改进PR 听写

如何创建你的第一个多行代码snippet 论坛分享

我的快捷键设置

10 basic vim command

how to use mac to snapshot screen

vim medium

install kite for vim
  • install Kite

  • select vim as editor during installation process

  • go to local setting and install vim and neovim plugins

  • then ready to use kite with vim

vim cursor moving

0 = go to start of a line

$ = go to end of a line

H = go to top of a window

L = go to bottle of a window

M = go to middle of a window

G = go to the end of a file

gg = go to the first line of a file

20G = go to the 20th line of a file

e = next word

b = previous word

( = previous sentence

) = next sentence

{ = previous paragraph or block

} = next paragraph or block

`` = go to previous edit place

Monosnap for video
  1. set 5 frame/second

  2. high quality

  3. capture mouse cursor and clicks

  4. it will be small enough

  5. it can also create gif from movie too

如何使用git merge

git help merge # to check out how to use git merge

# inside exp branch by `git checkout exp`, run the following to merge with master

git merge master

# then run `git commit -a -m "merge"` to finish it up

.pdbrc.py

"""

This is an example configuration file for pdb++.

Actually, it is what the author uses daily :-). Put it into ~/.pdbrc.py to use

it.

"""

import readline

import pdb

class Config(pdb.DefaultConfig):

filename_color = pdb.Color.yellow

truncate_long_lines = False # so you get all content insight 

highlight = True

sticky_by_default = True

line_number_color = pdb.Color.red

filename_color = pdb.Color.yellow

use_pygments = True

bg = 'light'

current_line_color = 1 # white arrow

Looper for youtube
  • chrome extension : looper for youtube

  • set automaticall loop all videos

use atom with Hydrogen
  1. atom core packages

  2. install hydrogen and its extensions (may not use at all though)

  3. install autocompletion python

  4. atom beautify

  5. source activate fastai

  6. go to a folder and then atom

如何将youtube sbv字幕转化为srt
  • 在youtube翻译字幕页面下载你的翻译sbv文件

  • 前往https://captionsconverter.com/ 做转化

  • 前往B站字幕上传你的字幕

翻译Youtube字幕常用快捷键
  • 将鼠标放置在主输入栏,翻译即可

  • shift + space = 暂停/播放

  • shift + arrow left/right = 后退/前进

  • 如要修改,前往具体字幕栏修改

如何去除YouTube字幕翻译时的卡顿
  • 先下载空白的YouTube提供的sbv字幕

  • 删除所有时间设置

  • 再重新上传回去

如何在iterm2中切屏分屏跳跃

shift + cmd + d = 横切屏幕

opt + cmd + up/down arrow = 跳屏

cmd + w = 关屏

最常用的terminal commands

最常用的terminal commands


# find out the size of directory folders

du -sh *  

# move cursor to the front or end of a line

ctrl + a = to the end of a line

ctrl + e = to the start of a line

ctrl + u = clear the line before the cursor

ctrl + k = clear the line after the cursor

cmd + k = clear the terminal

ctrl + f = move forward a character

ctrl + b = backward

esc + f = move forward by a word 

esc + b = move backward by a word

如何fastai本地安装

如何安装常用软件

  • 下载安装conda

  • 下载最新Conda, Mac选择pkg比较方便

  • 双击安装

  • 更新 condo update conda outside condo env

  • 创建独立工作环境

  • conda create -n fastai python=3 或者明确一个版本3.5

  • conda activate fastai 开启实验环境

  • conda deactivate 关闭实验环境

  • conda remove --name fastai --all 删除环境

  • 下载安装pdbpp 适配python 3.6均可3.7(可能只要是fastai dev 版本,就行)

  • conda install pdbpp is a must

  • not pip3 install pdbpp

  • 下载安装Jupyter notebook

  • 更新 pip: python3 -m pip install --upgrade pip

  • 下载更新Jupyter: python3 -m pip install jupyter

  • 下载安装 Pytorch和fastai libraries

  • 一步安装:conda install -c pytorch -c fastai fastai pytorch

  • 更新 conda update conda -y outside env

  • 更新 conda update -c fastai fastai inside env

  • 检验 conda list pip show

  • 卸载 conda uninstall fastai

  • developer install

  • see https://github.com/fastai/fastai#developer-install


git clone fastai-fork

cd fastai-fork

tools/run-after-git-clone

pip install -e ".[dev]"

vim basics to start

Vim basics

learnt from this video by tutorialLinux


:q ; just quit

:w ; save

:wq ; save and quit

:q! ; quit without saving

i ; go into insert mode to write code

ecs ; go back to command mode

dd ; from command mode to delete a line

3dd ; delete 3 lines 

u ; undo last action

ctrl + r ; redo action

/search_word ; to search a word inside a file

n ; to move to the next finding of your search

shift + n ; to move back the previous finding

:%s/search_word/replace_word/gc ; replace one by one

:%s/search_word/replace_word/g ; replace all at once

simple workflow

  • use search to go around quicky and i to insert and u to delete
如何用上下键跳跃5行代码

go to .vimrc, copy the following


noremap &lt;Up&gt; 5k

noremap &lt;Down&gt; 5j

then, just use arrow up or down

用vim找pdbpp中运行的代码 vim find codelines in pdbpp
  1. :find folder/filename

  2. press esc

  3. type line number

  4. shift + g

vim如何剪切,复制,粘贴,保存

vim如何剪切,复制,粘贴,保存


: how to cut, under normal mode

: 1. put cursor to where you want to cut

: 2. press v and move cursor to select characters 

: 2. press V and move cursor to select lines

: 3. press d to cut, press y to copy

: 4. move to where to paste, 

: 5; press P to paste before cursor

: 5: press p to paset after cursor

: 6. insert mode, press :w and enter

如何做vim常规搜索

文本内如何做vim常规搜索

Searching | Vim Tips Wiki | FANDOM powered by Wikia


/ls ;; 我们在搜索ls, 前面不要有space空格

?*.ls

/path.ls

;; inside .vimrc

set ignorecase

如何退出vim

如何退出vim


:q ; to quit without save

:q! ; to quit without save

:wq ; save and quit 

如何对文件夹做tag

如何对文件夹做tag


; terminal文件夹下输入 vim 

; 再输入 :MT

; 尝试搜索untar_data

:tag untar ;tab to complete

如何探索代码

如何探索代码


; 将鼠标放在要探索的code上

ctrl + ] ;= dive in

ctrl + t ;= pull back

ctrl + w, ctrl + ] ;= dive in from another horizontal split

ctrl + w, up or dn ;= switch between splits

ctrl + \ ;= dive in from a new tab 

ctrl + a, ;left or right ;= switch between tabs

如何寻找文件和文件夹搜索

如何寻找文件和文件夹搜索


:find pathlib ; 寻找pathlib所在文件

- ; 调入上一级文件夹路径

:b# ; 从打开的文档中跳回上一次打开的路径

:tag Path ; 进入文件后再搜索

如何展开和折叠

如何展开和折叠


za ;将鼠标放在+-

如何知道当前所在文件地址

如何知道当前所在文件地址


:F ; tab to complete and enter

安装下载 vim

安装下载 vim


brew install vim

brew upgrade vim

vim # to run vim

设置 vim source

设置 vim source


nano ~/.vimrc

安装 ctags

安装 ctags


brew install ctags

查看 .vimrc

查看.vimrc


set tags=tags

set foldcolumn=3

set foldmethod=indent

set ignorecase

command FileAddress echo expand('%:p')

syntax on

set background=dark

filetype indent plugin on

""""" current millenium

set nocompatible

syntax enable

filetype plugin on

""""" file finder or fuzzy search

set path+=**

""""" display all matching files when tab

set wildmenu

""""" Tag Jumping

command! MakeTags !ctags -R .

command MT MakeTags

""""" tag jump with new tab horizontally or vertically

map &lt;C-\&gt; :tab split&lt;CR&gt;:exec("tag ".expand("&lt;cword&gt;"))&lt;CR&gt;

"""" switch tabs in vim 

map &lt;C-a&gt;&lt;up&gt; :tabr&lt;cr&gt;

map &lt;C-a&gt;&lt;down&gt; :tabl&lt;cr&gt;

map &lt;C-a&gt;&lt;left&gt; :tabp&lt;cr&gt;

map &lt;C-a&gt;&lt;right&gt; :tabn&lt;cr&gt;

"""""""""""""""" make presentation with vim files

au VimEnter no_plugins.vim setl window=66

au VimEnter no_plugins.vim normal 8Gzz

au VimEnter no_plugins.vim command! GO normal M17jzzH

au VimEnter no_plugins.vim command! BACK normal M17kzzH

au VimEnter no_plugins.vim command! RUN execute getline(".")

" au VimEnter no_plugins.vim unmap H

" au VimEnter no_plugins.vim unmap L

" why dont these work :(

au VimEnter no_plugins.vim nnoremap ^f :GO&lt;CR&gt;

au VimEnter no_plugins.vim nnoremap ^b :BACK&lt;CR&gt;

Conda

Conda


# download miniconda https://docs.conda.io/en/latest/miniconda.html

conda --version # check version:

conda update conda # update conda: , install outside env

conda create -n mesa-abm python=3.6 anaconda # build environment

source activate mesa-abm

source deactivate

conda info --envs # check envs

conda env list # all envs to view

conda create --name new_env --clone existed_env # clone an env

conda remove --name old_env --all # delete an env

conda env export &gt; environment.yml # 输出env

conda env create -f environment.yml # build env from yml

Jupyter notebook install

Jupyter notebook


# If you have Python 3 installed (which is recommended):

python3 -m pip install --upgrade pip

python3 -m pip install jupyter

jupyter notebook # to start 

如何撤回本地和推送的commit

如何撤回本地和推送的commit


git checkout -- filename # 撤回未commit的changes

git reset --hard HEAD~1 # 撤回已经commit的changes

git push origin +master

如何免去用户名和密码

如何免去用户名和密码


# Permanently authenticating with Git repositories

$ git config credential.helper store

$ git push https://github.com/repo.git

Username for 'https://github.com': &lt;USERNAME&gt;

Password for 'https://USERNAME@github.com': &lt;PASSWORD&gt;

如何快速git push

如何快速git push


# 一步完成

lazygit 'message'

# 分步骤操作

# create a new repo on github

# go to your Mac directory 

git init

git add README.md

git commit -m "first commit"

git remote add origin official-repo.git

git push -u origin master

git reset # to undo git add .

如何在原fastai repo和你的fork repo之间更新?

如何在原fastai repo和你的fork repo之间更新?


# 一步完成

lazyupdate

# 分步骤操作

# step1: fork from official

# step2: git clone from your fork

git clone https://github.com/EmbraceLife/my-fork

cd my_fork

tools/run-after-git-clone # fastai tools

git remote add upstream official-url-git # link to official repo

git remote -v # check all branches local and remote

git pull upstream master # pull from official repo, or 

######## suggested by fastai is better I guess

git fetch upstream

git checkout master

git merge --no-edit upstream/master

git push

######## suggested by fastai

git push # update my-fork 

git pull # pull from my-fork

如何创建branch并将master更新给branch

如何创建branch, make changes and git push to cloud


git branch # check all branches

git branch new_branch_name # create a branch from where we are

git branch -m a_new_name # rename

git branch -d branch_to_go # delete

git checkout new_branch # switch to a new branch

# make changes, do commit, then push with the following code, it won't affect master branch!!!

git push --set-upstream origin new-branch-name # 

git push origin --delete new_branch_name # to delete a branch remote in github

svn checkout url-folder-replace-tree/master-with-trunk # only download part of a repo

如何做版本内容修改和测试

如何做版本内容修改和测试


conda uninstall -y fastai

cd fastai-fork

tools/run-after-git-clone

pip install -e ".[dev]"

# 做版本内容修改,接下来做测试

## 如果是源代码测试

make test

pytest

## 如果是docsrc 测试 (无需!!!)

cd docs_src

./run_tests.sh

ipdb

ipdb


python -m pdb file-name.py

# 原来进入代码,输入insert import pdb; pdb.set_trace() 来debug已经不需要了

sticky # 看到全局代码

ll # 从debug跳回到全局代码

# l 20

# l 1, 20: see line from 1 to 20

s # step into a function

n # 运行下一行

w # call stack, where I started and where I am in source code, d go down a stack, u to go up a stack

b 88 # 运行到88行,暂停

# b file.py:41 or b func_name

# b 11, this_year==2017: conditional breakpoint, at line 11 to breakpoint, if this_year == 2017

cl 1 # 删除第一个breakpoint

r # 运行所在 function

c # 运行直到结束

q # 终止

? # 查看文档

hit return # 重复上一次操作

pp variable_name # 友好打印 该变量

# 完成当前loop: until

构建bash_profile

构建bash_profile


cd # go to home directory

nano .bash_profile # go inside .bash_profile:

alias ex='cd /Users/Natsume/Documents/experiments; conda activate fastai'

alias ft='cd /Users/Natsume/Documents/fastai_treasures/plantseedling/; conda activate fastai'

alias v3='cd /Users/Natsume/Documents/course-v3/nbs/dl1; conda activate fastai'

alias fastai='cd /Users/Natsume/Documents/fastai; conda activate fastai'

alias sfastai='cd /Users/Natsume/miniconda3/envs/fastai/lib/python3.7/site-packages/fastai'

alias pdbpp='python -m pdb'

alias de='conda deactivate'

alias xcode="open -a Xcode"

alias jn='jupyter notebook'

function lazygit() {

git add .

git commit -a -m "$1"

git push

}

export PS1="\w "

export LC_ALL=zh_CN.UTF-8

export LANG=zh_CN.UTF-8

export LC_ALL=en_US.UTF-8

export LANG=en_US.UTF-8

# added by Anaconda3 5.2.0 installer

export PATH="/anaconda3/bin:$PATH"

# added by Miniconda3 4.5.12 installer

# &gt;&gt;&gt; conda init &gt;&gt;&gt;

# !! Contents within this block are managed by 'conda init' !!

__conda_setup="$(CONDA_REPORT_ERRORS=false '/Users/Natsume/miniconda3/bin/conda' shell.bash hook 2&gt; /dev/null)"

if [ $? -eq 0 ]; then

\eval "$__conda_setup"

else

if [ -f "/Users/Natsume/miniconda3/etc/profile.d/conda.sh" ]; then

. "/Users/Natsume/miniconda3/etc/profile.d/conda.sh"

CONDA_CHANGEPS1=false conda activate base

else

\export PATH="/Users/Natsume/miniconda3/bin:$PATH"

fi

fi

unset __conda_setup

# &lt;&lt;&lt; conda init &lt;&lt;&lt;

# added by Miniconda3 4.5.12 installer

# &gt;&gt;&gt; conda init &gt;&gt;&gt;

# !! Contents within this block are managed by 'conda init' !!

__conda_setup="$(CONDA_REPORT_ERRORS=false '/Users/Natsume/miniconda3/bin/conda' shell.bash hook 2&gt; /dev/null)"

if [ $? -eq 0 ]; then

\eval "$__conda_setup"

else

if [ -f "/Users/Natsume/miniconda3/etc/profile.d/conda.sh" ]; then

. "/Users/Natsume/miniconda3/etc/profile.d/conda.sh"

CONDA_CHANGEPS1=false conda activate base

else

\export PATH="/Users/Natsume/miniconda3/bin:$PATH"

fi

fi

unset __conda_setup

# &lt;&lt;&lt; conda init &lt;&lt;&lt;

构建pdbrc

构建pdbrc

如何构建和安装pdbrc video

如何使用pdbpp来实验代码


## located at ~ directory, named .pdbrc, no need for source, just save it

alias dr pp dir(%1) # 查看everything underneath the object

alias dt pp %1.__dict__ # 查看object's dictionaries

alias pdt for k, v in %1.items(): print(k, ": ", v) # 查看一个纯 python dictionary

alias loc locals().keys() # local variables

alias doc from inspect import getdoc; from pprint import pprint; pprint(getdoc(%1)) # documents

alias sources from inspect import getsourcelines; from pprint import pprint; pprint(getsourcelines(%1)) # source code

alias module from inspect import getmodule; from pprint import pprint; pprint(getmodule(%1)) # module name

alias fullargs from inspect import getfullargspec; from pprint import pprint; pprint(getfullargspec(%1)) # all arguments names

alias opt_param optimizer.param_groups[0]['params'][%1] # all parameters

alias opt_grad optimizer.param_groups[0]['params'][%1].grad # all gradients of parameters

Jupyter notebook extensions

Jupyter notebook extensions

3 steps to install


conda install jupyter_contrib_nbextensions

jupyter contrib nbextension install --user

jupyter nbextension enable toc2/main # in terminal or notebook cell, both are fine

# edit/notebook_config (at bottom of the droplist)

jn color theme

jn color theme


conda install jupyterthemes

jt -t onedork 

#| grade3 | oceans16 | chesterish | monokai | solarizedl | solarizedd

youtube-dl

youtube-dl

youtube-dl


--write-sub Write subtitle file

--write-auto-sub Write automatic subtitle file (YouTube only)

--all-subs Download all the available subtitles of the video

--list-subs List all available subtitles for the video

--sub-format FORMAT Subtitle format, accepts formats preference, for example: "srt" or "ass/srt/best"

--sub-lang LANGS Languages of the subtitles to download (optional) separated by commas, use IETF language tags like 'en

youtube-dl --write-auto-sub --sub-lang en --sub-format srt https://youtu.be/1ZhtwInuOD0

youtube-dl -f 'best[ext=mp4]' --write-auto-sub --sub-lang en --sub-format srt https://www.youtube.com/playlist?list=PLfYUBJiXbdtSIJb-Qd3pw0cqCbkGeS0xn

transcript transform

其他参考链接

其他参考链接

How to Customize your Terminal Prompt | OSXDaily

inspect — Inspect live objects — Python 3.7.2 documentation

20 Terminal shortcuts developers need to know - TechRepublic

如何修改谷歌浏览器语言设置for colab

如何为视频做语音解说

如何为视频做语音解说

  • 使用ytcropper做视频截取,循环播放

  • mac音量调到最低

  • 用quicktime做屏幕录制,提供语音解读,音量调节适中

Tabular models

所需library

所需library

from fastai.tabular import *
pandas是必备

pandas是必备

Tabular data should be in a Pandas DataFrame.

下载数据

下载数据

path = untar_data(URLs.ADULT_SAMPLE)
df = pd.read_csv(path/'adult.csv')
预制 `dep_var`, `cat_names`, `cont_names`, `procs`

预制 dep_var, cat_names, cont_names, procs

dep_var = 'salary'
cat_names = ['workclass', 'education', 'marital-status', 'occupation', 'relationship', 'race']
cont_names = ['age', 'fnlwgt', 'education-num']
procs = [FillMissing, Categorify, Normalize]
构建test 的data source

构建test 的data source

test = TabularList.from_df(df.iloc[800:1000].copy(), 
                           path=path, 
                           cat_names=cat_names, 
                           cont_names=cont_names)
在df和test data source基础上构建databunch

在df和test data source基础上构建databunch

data = (TabularList.from_df(df, path=path, cat_names=cat_names, cont_names=cont_names, procs=procs)
                           .split_by_idx(list(range(800,1000)))
                           .label_from_df(cols=dep_var)
                           .add_test(test)
                           .databunch())
展示10行batch数据样本

展示10行batch数据样本

data.show_batch(rows=10)
workclass education marital-status occupation relationship race education-num_na age fnlwgt education-num target
Private HS-grad Never-married Sales Not-in-family White False -1.2158 1.1004 -0.4224 <50k
? HS-grad Widowed ? Not-in-family White False 1.8627 0.0976 -0.4224 <50k
Self-emp-not-inc HS-grad Never-married Craft-repair Own-child Black False 0.0303 0.2092 -0.4224 <50k
Private HS-grad Married-civ-spouse Protective-serv Husband White False 1.5695 -0.5938 -0.4224 <50k
Private HS-grad Married-civ-spouse Handlers-cleaners Husband White False -0.9959 -0.0318 -0.4224 <50k
Private 10th Married-civ-spouse Farming-fishing Wife White False -0.7027 0.6071 -1.5958 <50k
Private HS-grad Married-civ-spouse Machine-op-inspct Husband White False 0.1036 -0.0968 -0.4224 <50k
Private Some-college Married-civ-spouse Exec-managerial Own-child White False -0.7760 -0.6653 -0.0312 >=50k
State-gov Some-college Never-married Tech-support Own-child White False -0.8493 -1.4959 -0.0312 <50k
Private 11th Never-married Machine-op-inspct Not-in-family White False -1.0692 -0.9516 -1.2046 <50k
构建tabular learner模型

构建tabular learner模型

learn = tabular_learner(data, layers=[200,100], metrics=accuracy)
训练

训练

learn.fit(1, 1e-2)

Total time: 00:03

epoch train_loss valid_loss accuracy
1 0.354604 0.378520 0.820000

Inference

如何做tabular data预测

如何做tabular data预测

row = df.iloc[0]
learn.predict(row)
(Category >=50k, tensor(1), tensor([0.4402, 0.5598]))
2 Likes

MNIST SGD

所需library

所需library

%matplotlib inline
from fastai.basics import *
点击下载数据集

点击下载数据集

Get the ‘pickled’ MNIST dataset from http://deeplearning.net/data/mnist/mnist.pkl.gz. We’re going to treat it as a standard flat dataset with fully connected layers, rather than using a CNN.

查看数据文件夹

查看数据文件夹

path = Config().data_path()/'mnist'
path.ls()
[PosixPath('/home/ubuntu/.fastai/data/mnist/mnist.pkl.gz')]
解压pkl数据包

解压pkl数据包

with gzip.open(path/'mnist.pkl.gz', 'rb') as f:
    ((x_train, y_train), (x_valid, y_valid), _) = pickle.load(f, encoding='latin-1')
展示图片和训练数据shape

展示图片和训练数据shape

plt.imshow(x_train[0].reshape((28,28)), cmap="gray")
x_train.shape
(50000, 784)

output_12_1

将训练和验证数据转化为torch.tensor

将训练和验证数据转化为torch.tensor

x_train,y_train,x_valid,y_valid = map(torch.tensor, (x_train,y_train,x_valid,y_valid))
n,c = x_train.shape
x_train.shape, y_train.min(), y_train.max()
(torch.Size([50000, 784]), tensor(0), tensor(9))

In lesson2-sgd we did these things ourselves:

x = torch.ones(n,2) 
def mse(y_hat, y): return ((y_hat-y)**2).mean()
y_hat = x@a

Now instead we’ll use PyTorch’s functions to do it for us, and also to handle mini-batches (which we didn’t do last time, since our dataset was so small).

将X与Y(torch.tensor)整合成TensorDataset

将X与Y(torch.tensor)整合成TensorDataset

bs=64
train_ds = TensorDataset(x_train, y_train)
valid_ds = TensorDataset(x_valid, y_valid)
将训练和验证集的TensorDataset 整合成DataBunch

将训练和验证集的TensorDataset 整合成DataBunch

data = DataBunch.create(train_ds, valid_ds, bs=bs)
从训练集DataBunch中一个一个提取数据点

从训练集DataBunch中一个一个提取数据点

x,y = next(iter(data.train_dl))
x.shape,y.shape
(torch.Size([64, 784]), torch.Size([64]))
创建模型的正向传递部分

创建模型的正向传递部分

class Mnist_Logistic(nn.Module):
    def __init__(self):
        super().__init__()
        self.lin = nn.Linear(784, 10, bias=True)

    def forward(self, xb): return self.lin(xb)
启用GPU机制

启用GPU机制

model = Mnist_Logistic().cuda()
查看模型

查看模型

model
Mnist_Logistic(
  (lin): Linear(in_features=784, out_features=10, bias=True)
)
调用模型中的lin层

调用模型中的lin层

model.lin
Linear(in_features=784, out_features=10, bias=True)
模型输出值的shape

模型输出值的shape

model(x).shape
torch.Size([64, 10])
调取模型每一层的参数,查看shape

调取模型每一层的参数,查看shape

[p.shape for p in model.parameters()]
[torch.Size([10, 784]), torch.Size([10])]
设置学习率

设置学习率

lr=2e-2
调用分类问题损失函数

调用分类问题损失函数

loss_func = nn.CrossEntropyLoss()
一次正向反向传递计算函数详解

一次正向反向传递计算函数详解

def update(x,y,lr):
    wd = 1e-5
    y_hat = model(x)
    # 设置 weight decay
    w2 = 0.
    # 计算 weight decay
    for p in model.parameters(): w2 += (p**2).sum()
    # 将 weight decay 添加到 常规损失值公式中
    loss = loss_func(y_hat, y) + w2*wd
    # 求导
    loss.backward()

    # 利用导数更新参数
    with torch.no_grad():
        for p in model.parameters():
            p.sub_(lr * p.grad)
            p.grad.zero_()
    # 输出损失值
    return loss.item()
对训练集中每一个数据点做一次正反向传递(即SGD),收集损失值

对训练集中每一个数据点做一次正反向传递(即SGD),收集损失值

losses = [update(x,y,lr) for x,y in data.train_dl]
将损失值作图

将损失值作图

plt.plot(losses);

output_43_0

构建一个2层模型,第一层含非线性激活函数ReLU

构建一个2层模型,第一层含非线性激活函数ReLU

class Mnist_NN(nn.Module):
    def __init__(self):
        super().__init__()
        self.lin1 = nn.Linear(784, 50, bias=True)
        self.lin2 = nn.Linear(50, 10, bias=True)

    def forward(self, xb):
        x = self.lin1(xb)
        x = F.relu(x)
        return self.lin2(x)
开启GPU设置

开启GPU设置

model = Mnist_NN().cuda()
用SGD计算获取训练集的损失值,并作图

用SGD计算获取训练集的损失值,并作图

losses = [update(x,y,lr) for x,y in data.train_dl]
plt.plot(losses);

output_50_0

再次开启模型的GPU计算模式

再次开启模型的GPU计算模式

model = Mnist_NN().cuda()
正反向传递中加入Adam优化算法和opt.step()取代手动参数更新公式

正反向传递中加入Adam优化算法和opt.step()取代手动参数更新公式

def update(x,y,lr):
    opt = optim.Adam(model.parameters(), lr)
    y_hat = model(x)
    loss = loss_func(y_hat, y)
    loss.backward()
    opt.step()
    opt.zero_grad()
    return loss.item()
对训练集做SGD,收集损失值,并作图

对训练集做SGD,收集损失值,并作图

losses = [update(x,y,1e-3) for x,y in data.train_dl]
plt.plot(losses);

output_57_0

采用fastai Learner方式进行建模

采用fastai Learner方式进行建模

learn = Learner(data, Mnist_NN(), loss_func=loss_func, metrics=accuracy)
作图寻找学习率最优值

作图寻找学习率最优值

learn.lr_find()
learn.recorder.plot()
LR Finder is complete, type {learner_name}.recorder.plot() to see the graph.

output_61_2

挑选最优值学习率,进行训练

挑选最优值学习率,进行训练

learn.fit_one_cycle(1, 1e-2)

Total time: 00:03

epoch train_loss valid_loss accuracy
1 0.129131 0.125927 0.963500
画出学习率和momentum图

画出学习率和momentum图

learn.recorder.plot_lr(show_moms=True)

画出损失值(训练vs验证)图

画出损失值(训练vs验证)图

learn.recorder.plot_losses()

output_67_0

Lesson 6: pets revisited

三行魔法代码和所需library

三行魔法代码和所需library

%reload_ext autoreload
%autoreload 2
%matplotlib inline

from fastai.vision import *
设置批量大小

设置批量大小

bs = 64
下载数据,获取图片文件夹地址

下载数据,获取图片文件夹地址

path = untar_data(URLs.PETS)/'images'

Data augmentation

对图片做特定处理

对图片做特定处理

tfms = get_transforms(max_rotate=20, max_zoom=1.3, max_lighting=0.4, max_warp=0.4,
                      p_affine=1., p_lighting=1.)
查看get_transforms文档

查看get_transforms文档

doc(get_transforms)
构建数据src

构建数据src

src = ImageList.from_folder(path).random_split_by_pct(0.2, seed=2)
创建一个定制函数来构建DataBunch

创建一个定制函数来构建DataBunch

def get_data(size, bs, padding_mode='reflection'):
    return (src.label_from_re(r'([^/]+)_\d+.jpg$')
           .transform(tfms, size=size, padding_mode=padding_mode)
           .databunch(bs=bs).normalize(imagenet_stats))
展示同一张图片的各种变形效果(padding=0)

展示同一张图片的各种变形效果(padding=0)

data = get_data(224, bs, 'zeros')
def _plot(i,j,ax):
    x,y = data.train_ds[3]
    x.show(ax, y=y)

plot_multi(_plot, 3, 3, figsize=(8,8))

output_19_0

展示同一张图片的各种变形效果(padding=reflection)

展示同一张图片的各种变形效果(padding=reflection)

data = get_data(224,bs)
plot_multi(_plot, 3, 3, figsize=(8,8))

output_22_0

Train a model

释放内存空间

释放内存空间

gc.collect()
用迁移学习构建模型 (bn_final=True)

用迁移学习构建模型 (bn_final=True)

learn = create_cnn(data, models.resnet34, metrics=error_rate, bn_final=True)
训练模型 (pct_start=0.8)

训练模型 (pct_start=0.8)

learn.fit_one_cycle(3, slice(1e-2), pct_start=0.8)

Total time: 01:22

epoch train_loss valid_loss error_rate
1 2.573282 1.364505 0.271989
2 1.545074 0.377077 0.094046
3 0.937992 0.270508 0.068336
解冻,再训练 max_lr=slice(1e-6,1e-3)

解冻,再训练 max_lr=slice(1e-6,1e-3)

learn.unfreeze()
learn.fit_one_cycle(2, max_lr=slice(1e-6,1e-3), pct_start=0.8)

Total time: 00:55

epoch train_loss valid_loss error_rate
1 0.721187 0.294177 0.058187
2 0.675999 0.285875 0.050744
改变数据的图片大小

改变数据的图片大小

data = get_data(352,bs)
learn.data = data
再训练 max_lr=slice(1e-6,1e-4)

再训练 max_lr=slice(1e-6,1e-4)

learn.fit_one_cycle(2, max_lr=slice(1e-6,1e-4))

Total time: 01:37

epoch train_loss valid_loss error_rate
1 0.627055 0.286791 0.058863
2 0.602765 0.286951 0.058863
保存模型

保存模型

learn.save('352')

Convolution kernel

改变数据批量大小 (缩小)

改变数据批量大小 (缩小)

data = get_data(352,16)
加载上次训练的模型

加载上次训练的模型

learn = create_cnn(data, models.resnet34, metrics=error_rate, bn_final=True).load('352')
展示验证集中的第一个数据点(图和label)

展示验证集中的第一个数据点(图和label)

idx=0
x,y = data.valid_ds[idx]
x.show()
data.valid_ds.y[idx]
Category american_pit_bull_terrier

output_44_1

创建一个kernel or filter

创建一个kernel or filter

k = tensor([
    [0.  ,-5/3,1],
    [-5/3,-5/3,1],
    [1.  ,1   ,1],
]).expand(1,3,3,3)/6
k
tensor([[[[ 0.0000, -0.2778,  0.1667],
          [-0.2778, -0.2778,  0.1667],
          [ 0.1667,  0.1667,  0.1667]],

         [[ 0.0000, -0.2778,  0.1667],
          [-0.2778, -0.2778,  0.1667],
          [ 0.1667,  0.1667,  0.1667]],

         [[ 0.0000, -0.2778,  0.1667],
          [-0.2778, -0.2778,  0.1667],
          [ 0.1667,  0.1667,  0.1667]]]])
k.shape
torch.Size([1, 3, 3, 3])
从验证数据中提起一个数据点的图片tensor

从验证数据中提起一个数据点的图片tensor

t = data.valid_ds[0][0].data; t.shape
torch.Size([3, 352, 352])
将3D tensor变成4D

将3D tensor变成4D

t[None].shape
torch.Size([1, 3, 352, 352])
对这个4D tensor做filter处理

对这个4D tensor做filter处理

edge = F.conv2d(t[None], k)
显示filter处理结构

显示filter处理结构

show_image(edge[0], figsize=(5,5));

output_56_0

查看data.c

查看data.c

data.c
37
查看模型结构

查看模型结构

learn.model
Sequential(
  (0): Sequential(
    (0): Conv2d(3, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3), bias=False)
    (1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (2): ReLU(inplace)
    (3): MaxPool2d(kernel_size=3, stride=2, padding=1, dilation=1, ceil_mode=False)
    (4): Sequential(
      (0): BasicBlock(
        (conv1): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
        (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
        (relu): ReLU(inplace)
        (conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
        (bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      )
      (1): BasicBlock(
        (conv1): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
        (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
        (relu): ReLU(inplace)
        (conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
        (bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      )
      (2): BasicBlock(
        (conv1): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
        (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
        (relu): ReLU(inplace)
        (conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
        (bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      )
    )
    (5): Sequential(
      (0): BasicBlock(
        (conv1): Conv2d(64, 128, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
        (bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
        (relu): ReLU(inplace)
        (conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
        (bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
        (downsample): Sequential(
          (0): Conv2d(64, 128, kernel_size=(1, 1), stride=(2, 2), bias=False)
          (1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
        )
      )
      (1): BasicBlock(
        (conv1): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
        (bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
        (relu): ReLU(inplace)
        (conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
        (bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      )
      (2): BasicBlock(
        (conv1): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
        (bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
        (relu): ReLU(inplace)
        (conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
        (bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      )
      (3): BasicBlock(
        (conv1): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
        (bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
        (relu): ReLU(inplace)
        (conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
        (bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      )
    )
    (6): Sequential(
      (0): BasicBlock(
        (conv1): Conv2d(128, 256, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
        (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
        (relu): ReLU(inplace)
        (conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
        (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
        (downsample): Sequential(
          (0): Conv2d(128, 256, kernel_size=(1, 1), stride=(2, 2), bias=False)
          (1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
        )
      )
      (1): BasicBlock(
        (conv1): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
        (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
        (relu): ReLU(inplace)
        (conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
        (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      )
      (2): BasicBlock(
        (conv1): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
        (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
        (relu): ReLU(inplace)
        (conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
        (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      )
      (3): BasicBlock(
        (conv1): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
        (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
        (relu): ReLU(inplace)
        (conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
        (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      )
      (4): BasicBlock(
        (conv1): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
        (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
        (relu): ReLU(inplace)
        (conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
        (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      )
      (5): BasicBlock(
        (conv1): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
        (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
        (relu): ReLU(inplace)
        (conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
        (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      )
    )
    (7): Sequential(
      (0): BasicBlock(
        (conv1): Conv2d(256, 512, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
        (bn1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
        (relu): ReLU(inplace)
        (conv2): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
        (bn2): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
        (downsample): Sequential(
          (0): Conv2d(256, 512, kernel_size=(1, 1), stride=(2, 2), bias=False)
          (1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
        )
      )
      (1): BasicBlock(
        (conv1): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
        (bn1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
        (relu): ReLU(inplace)
        (conv2): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
        (bn2): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      )
      (2): BasicBlock(
        (conv1): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
        (bn1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
        (relu): ReLU(inplace)
        (conv2): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
        (bn2): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      )
    )
  )
  (1): Sequential(
    (0): AdaptiveConcatPool2d(
      (ap): AdaptiveAvgPool2d(output_size=1)
      (mp): AdaptiveMaxPool2d(output_size=1)
    )
    (1): Flatten()
    (2): BatchNorm1d(1024, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (3): Dropout(p=0.25)
    (4): Linear(in_features=1024, out_features=512, bias=True)
    (5): ReLU(inplace)
    (6): BatchNorm1d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (7): Dropout(p=0.5)
    (8): Linear(in_features=512, out_features=37, bias=True)
    (9): BatchNorm1d(37, eps=1e-05, momentum=0.01, affine=True, track_running_stats=True)
  )
)
打印模型总结

打印模型总结

print(learn.summary())
'======================================================================\nLayer (type)         Output Shape         Param #    Trainable \n======================================================================\nConv2d               [16, 64, 176, 176]   9408       False     \n______________________________________________________________________\nBatchNorm2d          [16, 64, 176, 176]   128        True      \n______________________________________________________________________\nReLU                 [16, 64, 176, 176]   0          False     \n______________________________________________________________________\nMaxPool2d            [16, 64, 88, 88]     0          False     \n______________________________________________________________________\nConv2d               [16, 64, 88, 88]     36864      False     \n______________________________________________________________________\nBatchNorm2d          [16, 64, 88, 88]     128        True      \n______________________________________________________________________\nReLU                 [16, 64, 88, 88]     0          False     \n______________________________________________________________________\nConv2d               [16, 64, 88, 88]     36864      False     \n______________________________________________________________________\nBatchNorm2d          [16, 64, 88, 88]     128        True      \n______________________________________________________________________\nConv2d               [16, 64, 88, 88]     36864      False     \n______________________________________________________________________\nBatchNorm2d          [16, 64, 88, 88]     128        True      \n______________________________________________________________________\nReLU                 [16, 64, 88, 88]     0          False     \n______________________________________________________________________\nConv2d               [16, 64, 88, 88]     36864      False     \n______________________________________________________________________\nBatchNorm2d          [16, 64, 88, 88]     128        True      \n______________________________________________________________________\nConv2d               [16, 64, 88, 88]     36864      False     \n______________________________________________________________________\nBatchNorm2d          [16, 64, 88, 88]     128        True      \n______________________________________________________________________\nReLU                 [16, 64, 88, 88]     0          False     \n______________________________________________________________________\nConv2d               [16, 64, 88, 88]     36864      False     \n______________________________________________________________________\nBatchNorm2d          [16, 64, 88, 88]     128        True      \n______________________________________________________________________\nConv2d               [16, 128, 44, 44]    73728      False     \n______________________________________________________________________\nBatchNorm2d          [16, 128, 44, 44]    256        True      \n______________________________________________________________________\nReLU                 [16, 128, 44, 44]    0          False     \n______________________________________________________________________\nConv2d               [16, 128, 44, 44]    147456     False     \n______________________________________________________________________\nBatchNorm2d          [16, 128, 44, 44]    256        True      \n______________________________________________________________________\nConv2d               [16, 128, 44, 44]    8192       False     \n______________________________________________________________________\nBatchNorm2d          [16, 128, 44, 44]    256        True      \n______________________________________________________________________\nConv2d               [16, 128, 44, 44]    147456     False     \n______________________________________________________________________\nBatchNorm2d          [16, 128, 44, 44]    256        True      \n______________________________________________________________________\nReLU                 [16, 128, 44, 44]    0          False     \n______________________________________________________________________\nConv2d               [16, 128, 44, 44]    147456     False     \n______________________________________________________________________\nBatchNorm2d          [16, 128, 44, 44]    256        True      \n______________________________________________________________________\nConv2d               [16, 128, 44, 44]    147456     False     \n______________________________________________________________________\nBatchNorm2d          [16, 128, 44, 44]    256        True      \n______________________________________________________________________\nReLU                 [16, 128, 44, 44]    0          False     \n______________________________________________________________________\nConv2d               [16, 128, 44, 44]    147456     False     \n______________________________________________________________________\nBatchNorm2d          [16, 128, 44, 44]    256        True      \n______________________________________________________________________\nConv2d               [16, 128, 44, 44]    147456     False     \n______________________________________________________________________\nBatchNorm2d          [16, 128, 44, 44]    256        True      \n______________________________________________________________________\nReLU                 [16, 128, 44, 44]    0          False     \n______________________________________________________________________\nConv2d               [16, 128, 44, 44]    147456     False     \n______________________________________________________________________\nBatchNorm2d          [16, 128, 44, 44]    256        True      \n______________________________________________________________________\nConv2d               [16, 256, 22, 22]    294912     False     \n______________________________________________________________________\nBatchNorm2d          [16, 256, 22, 22]    512        True      \n______________________________________________________________________\nReLU                 [16, 256, 22, 22]    0          False     \n______________________________________________________________________\nConv2d               [16, 256, 22, 22]    589824     False     \n______________________________________________________________________\nBatchNorm2d          [16, 256, 22, 22]    512        True      \n______________________________________________________________________\nConv2d               [16, 256, 22, 22]    32768      False     \n______________________________________________________________________\nBatchNorm2d          [16, 256, 22, 22]    512        True      \n______________________________________________________________________\nConv2d               [16, 256, 22, 22]    589824     False     \n______________________________________________________________________\nBatchNorm2d          [16, 256, 22, 22]    512        True      \n______________________________________________________________________\nReLU                 [16, 256, 22, 22]    0          False     \n______________________________________________________________________\nConv2d               [16, 256, 22, 22]    589824     False     \n______________________________________________________________________\nBatchNorm2d          [16, 256, 22, 22]    512        True      \n______________________________________________________________________\nConv2d               [16, 256, 22, 22]    589824     False     \n______________________________________________________________________\nBatchNorm2d          [16, 256, 22, 22]    512        True      \n______________________________________________________________________\nReLU                 [16, 256, 22, 22]    0          False     \n______________________________________________________________________\nConv2d               [16, 256, 22, 22]    589824     False     \n______________________________________________________________________\nBatchNorm2d          [16, 256, 22, 22]    512        True      \n______________________________________________________________________\nConv2d               [16, 256, 22, 22]    589824     False     \n______________________________________________________________________\nBatchNorm2d          [16, 256, 22, 22]    512        True      \n______________________________________________________________________\nReLU                 [16, 256, 22, 22]    0          False     \n______________________________________________________________________\nConv2d               [16, 256, 22, 22]    589824     False     \n______________________________________________________________________\nBatchNorm2d          [16, 256, 22, 22]    512        True      \n______________________________________________________________________\nConv2d               [16, 256, 22, 22]    589824     False     \n______________________________________________________________________\nBatchNorm2d          [16, 256, 22, 22]    512        True      \n______________________________________________________________________\nReLU                 [16, 256, 22, 22]    0          False     \n______________________________________________________________________\nConv2d               [16, 256, 22, 22]    589824     False     \n______________________________________________________________________\nBatchNorm2d          [16, 256, 22, 22]    512        True      \n______________________________________________________________________\nConv2d               [16, 256, 22, 22]    589824     False     \n______________________________________________________________________\nBatchNorm2d          [16, 256, 22, 22]    512        True      \n______________________________________________________________________\nReLU                 [16, 256, 22, 22]    0          False     \n______________________________________________________________________\nConv2d               [16, 256, 22, 22]    589824     False     \n______________________________________________________________________\nBatchNorm2d          [16, 256, 22, 22]    512        True      \n______________________________________________________________________\nConv2d               [16, 512, 11, 11]    1179648    False     \n______________________________________________________________________\nBatchNorm2d          [16, 512, 11, 11]    1024       True      \n______________________________________________________________________\nReLU                 [16, 512, 11, 11]    0          False     \n______________________________________________________________________\nConv2d               [16, 512, 11, 11]    2359296    False     \n______________________________________________________________________\nBatchNorm2d          [16, 512, 11, 11]    1024       True      \n______________________________________________________________________\nConv2d               [16, 512, 11, 11]    131072     False     \n______________________________________________________________________\nBatchNorm2d          [16, 512, 11, 11]    1024       True      \n______________________________________________________________________\nConv2d               [16, 512, 11, 11]    2359296    False     \n______________________________________________________________________\nBatchNorm2d          [16, 512, 11, 11]    1024       True      \n______________________________________________________________________\nReLU                 [16, 512, 11, 11]    0          False     \n______________________________________________________________________\nConv2d               [16, 512, 11, 11]    2359296    False     \n______________________________________________________________________\nBatchNorm2d          [16, 512, 11, 11]    1024       True      \n______________________________________________________________________\nConv2d               [16, 512, 11, 11]    2359296    False     \n______________________________________________________________________\nBatchNorm2d          [16, 512, 11, 11]    1024       True      \n______________________________________________________________________\nReLU                 [16, 512, 11, 11]    0          False     \n______________________________________________________________________\nConv2d               [16, 512, 11, 11]    2359296    False     \n______________________________________________________________________\nBatchNorm2d          [16, 512, 11, 11]    1024       True      \n______________________________________________________________________\nAdaptiveAvgPool2d    [16, 512, 1, 1]      0          False     \n______________________________________________________________________\nAdaptiveMaxPool2d    [16, 512, 1, 1]      0          False     \n______________________________________________________________________\nFlatten              [16, 1024]           0          False     \n______________________________________________________________________\nBatchNorm1d          [16, 1024]           2048       True      \n______________________________________________________________________\nDropout              [16, 1024]           0          False     \n______________________________________________________________________\nLinear               [16, 512]            524800     True      \n______________________________________________________________________\nReLU                 [16, 512]            0          False     \n______________________________________________________________________\nBatchNorm1d          [16, 512]            1024       True      \n______________________________________________________________________\nDropout              [16, 512]            0          False     \n______________________________________________________________________\nLinear               [16, 37]             18981      True      \n______________________________________________________________________\nBatchNorm1d          [16, 37]             74         True      \n______________________________________________________________________\n\nTotal params: 21831599\nTotal trainable params: 563951\nTotal non-trainable params: 21267648\n'

Heatmap

提取模型正向传递计算

提取模型正向传递计算

m = learn.model.eval();
提取一个数据点 (只用X部分)

提取一个数据点 (只用X部分)

xb,_ = data.one_item(x)
对数据点X部分做denormalization处理,在转化为图片格式

对数据点X部分做denormalization处理,在转化为图片格式

xb_im = Image(data.denorm(xb)[0])
对数据点X部分做GPU计算设置

对数据点X部分做GPU计算设置

xb = xb.cuda()
调用callbacks.hooks全部功能

调用callbacks.hooks全部功能

from fastai.callbacks.hooks import *
构建函数提取模型激活层数据

构建函数提取模型激活层数据

def hooked_backward(cat=y):
    with hook_output(m[0]) as hook_a: 
        with hook_output(m[0], grad=True) as hook_g:
            preds = m(xb)
            preds[0,int(cat)].backward()
    return hook_a,hook_g
hook_a,hook_g = hooked_backward()
提取激活层数据,纵向做均值处理

提取激活层数据,纵向做均值处理

acts  = hook_a.stored[0].cpu()
acts.shape
torch.Size([512, 11, 11])
avg_acts = acts.mean(0)
avg_acts.shape
torch.Size([11, 11])
构建heatmap作图函数

构建heatmap作图函数

def show_heatmap(hm):
    _,ax = plt.subplots()
    xb_im.show(ax)
    ax.imshow(hm, alpha=0.6, extent=(0,352,352,0),
              interpolation='bilinear', cmap='magma');
show_heatmap(avg_acts)

output_82_0

Grad-CAM

论文提出的制作heatmap方法

论文提出的制作heatmap方法

Paper: Grad-CAM: Visual Explanations from Deep Networks via Gradient-based Localization

案例1

案例1

grad = hook_g.stored[0][0].cpu()
grad_chan = grad.mean(1).mean(1)
grad.shape,grad_chan.shape
(torch.Size([512, 11, 11]), torch.Size([512]))
mult = (acts*grad_chan[...,None,None]).mean(0)
show_heatmap(mult)

output_89_0

案例2

案例2

fn = path/'../other/bulldog_maine.jpg' #Replace with your own image
x = open_image(fn); x
xb,_ = data.one_item(x)
xb_im = Image(data.denorm(xb)[0])
xb = xb.cuda()
hook_a,hook_g = hooked_backward()
acts = hook_a.stored[0].cpu()
grad = hook_g.stored[0][0].cpu()

grad_chan = grad.mean(1).mean(1)
mult = (acts*grad_chan[...,None,None]).mean(0)
show_heatmap(mult)

output_96_0

案例3: 通过处理数据类别,heatmap从聚焦猫到了狗

案例3: 通过处理数据类别,heatmap从聚焦猫到了狗

data.classes[0]
'american_bulldog'
hook_a,hook_g = hooked_backward(0)
acts = hook_a.stored[0].cpu()
grad = hook_g.stored[0][0].cpu()

grad_chan = grad.mean(1).mean(1)
mult = (acts*grad_chan[...,None,None]).mean(0)
show_heatmap(mult)

output_101_0

Lesson 6 Rossmann sales prediction

2行魔法代码

2行魔法代码

%reload_ext autoreload
%autoreload 2
所需library

所需library

from fastai.tabular import *

Data preparation

feature engineering

feature engineering

To create the feature-engineered train_clean and test_clean from the Kaggle competition data, run rossman_data_clean.ipynb. One important step that deals with time series is this:

add_datepart(train, "Date", drop=False)
add_datepart(test, "Date", drop=False)
调取feature engineering 之后数据

调取feature engineering 之后数据

path = Config().data_path()/'rossmann'
train_df = pd.read_pickle(path/'train_clean')
查看数据

查看数据

train_df.head().T
.dataframe tbody tr th:only-of-type { vertical-align: middle; }
.dataframe tbody tr th {
    vertical-align: top;
}

.dataframe thead th {
    text-align: right;
}
0 1 2 3 4
index 0 1 2 3 4
Store 1 2 3 4 5
DayOfWeek 5 5 5 5 5
Date 2015-07-31 2015-07-31 2015-07-31 2015-07-31 2015-07-31
Sales 5263 6064 8314 13995 4822
Customers 555 625 821 1498 559
Open 1 1 1 1 1
Promo 1 1 1 1 1
StateHoliday False False False False False
SchoolHoliday 1 1 1 1 1
Year 2015 2015 2015 2015 2015
Month 7 7 7 7 7
Week 31 31 31 31 31
Day 31 31 31 31 31
Dayofweek 4 4 4 4 4
Dayofyear 212 212 212 212 212
Is_month_end True True True True True
Is_month_start False False False False False
Is_quarter_end False False False False False
Is_quarter_start False False False False False
Is_year_end False False False False False
Is_year_start False False False False False
Elapsed 1438300800 1438300800 1438300800 1438300800 1438300800
StoreType c a a c a
Assortment a a a c a
CompetitionDistance 1270 570 14130 620 29910
CompetitionOpenSinceMonth 9 11 12 9 4
CompetitionOpenSinceYear 2008 2007 2006 2009 2015
Promo2 0 1 1 0 0
Promo2SinceWeek 1 13 14 1 1
... ... ... ... ... ...
Min_Sea_Level_PressurehPa 1015 1017 1017 1014 1016
Max_VisibilityKm 31 10 31 10 10
Mean_VisibilityKm 15 10 14 10 10
Min_VisibilitykM 10 10 10 10 10
Max_Wind_SpeedKm_h 24 14 14 23 14
Mean_Wind_SpeedKm_h 11 11 5 16 11
Max_Gust_SpeedKm_h NaN NaN NaN NaN NaN
Precipitationmm 0 0 0 0 0
CloudCover 1 4 2 6 4
Events Fog Fog Fog NaN NaN
WindDirDegrees 13 309 354 282 290
StateName Hessen Thueringen NordrheinWestfalen Berlin Sachsen
CompetitionOpenSince 2008-09-15 2007-11-15 2006-12-15 2009-09-15 2015-04-15
CompetitionDaysOpen 2510 2815 3150 2145 107
CompetitionMonthsOpen 24 24 24 24 3
Promo2Since 1900-01-01 2010-03-29 2011-04-04 1900-01-01 1900-01-01
Promo2Days 0 1950 1579 0 0
Promo2Weeks 0 25 25 0 0
AfterSchoolHoliday 0 0 0 0 0
BeforeSchoolHoliday 0 0 0 0 0
AfterStateHoliday 57 67 57 67 57
BeforeStateHoliday 0 0 0 0 0
AfterPromo 0 0 0 0 0
BeforePromo 0 0 0 0 0
SchoolHoliday_bw 5 5 5 5 5
StateHoliday_bw 0 0 0 0 0
Promo_bw 5 5 5 5 5
SchoolHoliday_fw 7 1 5 1 1
StateHoliday_fw 0 0 0 0 0
Promo_fw 5 1 5 1 1

93 rows × 5 columns

n = len(train_df); n
844338
构建一个小数据集样本

构建一个小数据集样本

Experimenting with a sample

idx = np.random.permutation(range(n))[:2000]
idx.sort()
small_train_df = train_df.iloc[idx[:1000]]
small_test_df = train_df.iloc[idx[1000:]]
small_cont_vars = ['CompetitionDistance', 'Mean_Humidity']
small_cat_vars =  ['Store', 'DayOfWeek', 'PromoInterval']
small_train_df = small_train_df[small_cat_vars + small_cont_vars + ['Sales']]
small_test_df = small_test_df[small_cat_vars + small_cont_vars + ['Sales']]
small_train_df.head()
.dataframe tbody tr th:only-of-type { vertical-align: middle; }
.dataframe tbody tr th {
    vertical-align: top;
}

.dataframe thead th {
    text-align: right;
}
Store DayOfWeek PromoInterval CompetitionDistance Mean_Humidity Sales
267 268 5 NaN 4520.0 67 7492
604 606 5 NaN 2260.0 61 7187
983 986 5 Feb,May,Aug,Nov 620.0 61 7051
1636 525 4 NaN 1870.0 55 9673
2348 123 3 NaN 16760.0 50 10007
small_test_df.head()
.dataframe tbody tr th:only-of-type { vertical-align: middle; }
.dataframe tbody tr th {
    vertical-align: top;
}

.dataframe thead th {
    text-align: right;
}
Store DayOfWeek PromoInterval CompetitionDistance Mean_Humidity Sales
420510 829 3 NaN 110.0 55 6802
420654 973 3 Jan,Apr,Jul,Oct 330.0 59 6644
420990 194 2 Feb,May,Aug,Nov 16970.0 55 4720
421308 512 2 Mar,Jun,Sept,Dec 590.0 72 6248
421824 1029 2 NaN 1590.0 64 8004
对cat_vars, cont_vars做categorify处理

对cat_vars, cont_vars做categorify处理

categorify = Categorify(small_cat_vars, small_cont_vars)
categorify(small_train_df)
categorify(small_test_df, test=True)
small_test_df.head()
.dataframe tbody tr th:only-of-type { vertical-align: middle; }
.dataframe tbody tr th {
    vertical-align: top;
}

.dataframe thead th {
    text-align: right;
}
Store DayOfWeek PromoInterval CompetitionDistance Mean_Humidity Sales
420510 NaN 3 NaN 110.0 55 6802
420654 973.0 3 Jan,Apr,Jul,Oct 330.0 59 6644
420990 NaN 2 Feb,May,Aug,Nov 16970.0 55 4720
421308 512.0 2 Mar,Jun,Sept,Dec 590.0 72 6248
421824 1029.0 2 NaN 1590.0 64 8004
查看数据categories文字与数字形式

查看数据categories文字与数字形式

small_train_df.PromoInterval.cat.categories
Index(['Feb,May,Aug,Nov', 'Jan,Apr,Jul,Oct', 'Mar,Jun,Sept,Dec'], dtype='object')
small_train_df['PromoInterval'].cat.codes[:5]
267    -1
604    -1
983     0
1636   -1
2348   -1
dtype: int8
处理数据缺失

处理数据缺失

fill_missing = FillMissing(small_cat_vars, small_cont_vars)
fill_missing(small_train_df)
fill_missing(small_test_df, test=True)
small_train_df[small_train_df['CompetitionDistance_na'] == True]
.dataframe tbody tr th:only-of-type { vertical-align: middle; }
.dataframe tbody tr th {
    vertical-align: top;
}

.dataframe thead th {
    text-align: right;
}
Store DayOfWeek PromoInterval CompetitionDistance Mean_Humidity Sales CompetitionDistance_na
185749 622 2 NaN 2300.0 93 4508 True

Preparing full data set

从pickle文件里提取全部训练和测试数据

从pickle文件里提取全部训练和测试数据

train_df = pd.read_pickle(path/'train_clean')
test_df = pd.read_pickle(path/'test_clean')
len(train_df),len(test_df)
(844338, 41088)
设置预处理,和全部的cat_vars, cont_vars

设置预处理,和全部的cat_vars, cont_vars

procs=[FillMissing, Categorify, Normalize]
cat_vars = ['Store', 'DayOfWeek', 'Year', 'Month', 'Day', 'StateHoliday', 'CompetitionMonthsOpen',
    'Promo2Weeks', 'StoreType', 'Assortment', 'PromoInterval', 'CompetitionOpenSinceYear', 'Promo2SinceYear',
    'State', 'Week', 'Events', 'Promo_fw', 'Promo_bw', 'StateHoliday_fw', 'StateHoliday_bw',
    'SchoolHoliday_fw', 'SchoolHoliday_bw']

cont_vars = ['CompetitionDistance', 'Max_TemperatureC', 'Mean_TemperatureC', 'Min_TemperatureC',
   'Max_Humidity', 'Mean_Humidity', 'Min_Humidity', 'Max_Wind_SpeedKm_h', 
   'Mean_Wind_SpeedKm_h', 'CloudCover', 'trend', 'trend_DE',
   'AfterStateHoliday', 'BeforeStateHoliday', 'Promo', 'SchoolHoliday']
设置训练数据成分

设置训练数据成分

dep_var = 'Sales'
df = train_df[cat_vars + cont_vars + [dep_var,'Date']].copy()
找出测试数据长度

找出测试数据长度

test_df['Date'].min(), test_df['Date'].max()
('2015-08-01', '2015-09-17')
根据测试数据两计算需要多少验证数据

根据测试数据两计算需要多少验证数据

cut = train_df['Date'][(train_df['Date'] == train_df['Date'][len(test_df)])].index.max()
cut
41395
valid_idx = range(cut)
df[dep_var].head()
0     5263
1     6064
2     8314
3    13995
4     4822
Name: Sales, dtype: int64
用TabluarList和df构建databunch

用TabluarList和df构建databunch

data = (TabularList.from_df(df, path=path, cat_names=cat_vars, cont_names=cont_vars, procs=procs,)
                .split_by_idx(valid_idx)
                .label_from_df(cols=dep_var, label_cls=FloatList, log=True)
                .add_test(TabularList.from_df(test_df, path=path, cat_names=cat_vars, cont_names=cont_vars))
                .databunch())
查看FloatList 与 log的使用

查看FloatList 与 log的使用

doc(FloatList)

Model

计算y range

计算y range

max_log_y = np.log(np.max(train_df['Sales'])*1.2)
y_range = torch.tensor([0, max_log_y], device=defaults.device)
构建tabular learner

构建tabular learner

learn = tabular_learner(data, layers=[1000,500], ps=[0.001,0.01], emb_drop=0.04, 
                        y_range=y_range, metrics=exp_rmspe)
查看模型

查看模型

learn.model
TabularModel(
  (embeds): ModuleList(
    (0): Embedding(1116, 81)
    (1): Embedding(8, 5)
    (2): Embedding(4, 3)
    (3): Embedding(13, 7)
    (4): Embedding(32, 11)
    (5): Embedding(3, 3)
    (6): Embedding(26, 10)
    (7): Embedding(27, 10)
    (8): Embedding(5, 4)
    (9): Embedding(4, 3)
    (10): Embedding(4, 3)
    (11): Embedding(24, 9)
    (12): Embedding(9, 5)
    (13): Embedding(13, 7)
    (14): Embedding(53, 15)
    (15): Embedding(22, 9)
    (16): Embedding(7, 5)
    (17): Embedding(7, 5)
    (18): Embedding(4, 3)
    (19): Embedding(4, 3)
    (20): Embedding(9, 5)
    (21): Embedding(9, 5)
    (22): Embedding(3, 3)
    (23): Embedding(3, 3)
  )
  (emb_drop): Dropout(p=0.04)
  (bn_cont): BatchNorm1d(16, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  (layers): Sequential(
    (0): Linear(in_features=233, out_features=1000, bias=True)
    (1): ReLU(inplace)
    (2): BatchNorm1d(1000, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (3): Dropout(p=0.001)
    (4): Linear(in_features=1000, out_features=500, bias=True)
    (5): ReLU(inplace)
    (6): BatchNorm1d(500, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (7): Dropout(p=0.01)
    (8): Linear(in_features=500, out_features=1, bias=True)
  )
)
查看数据内细节

查看数据内细节

len(data.train_ds.cont_names)
16
作图,寻找学习率最优值

作图,寻找学习率最优值

learn.lr_find()
LR Finder is complete, type {learner_name}.recorder.plot() to see the graph.
learn.recorder.plot()

output_58_0

训练模型 1e-3, wd=0.2

训练模型 1e-3, wd=0.2

learn.fit_one_cycle(5, 1e-3, wd=0.2)

Total time: 11:27

epoch train_loss valid_loss exp_rmspe
1 0.023587 0.020941 0.140551
2 0.017678 0.023431 0.132211
3 0.017453 0.016929 0.120169
4 0.012608 0.016296 0.109245
5 0.010222 0.011238 0.105433
learn.save('1')
画出损失值走势

画出损失值走势

learn.recorder.plot_losses(last=-1)

output_63_0

learn.load('1');
连续训练两次,每次5epochs,lr=3e-4

连续训练两次,每次5epochs,lr=3e-4

learn.fit_one_cycle(5, 3e-4)

Total time: 11:32

epoch train_loss valid_loss exp_rmspe
1 0.012223 0.014312 0.116988
2 0.012001 0.017789 0.117619
3 0.011402 0.035596 0.114396
4 0.010067 0.015125 0.113652
5 0.009148 0.031326 0.116344
learn.fit_one_cycle(5, 3e-4)

Total time: 11:31

epoch train_loss valid_loss exp_rmspe
1 0.011840 0.013236 0.110483
2 0.010765 0.057664 0.129586
3 0.010101 0.042744 0.111584
4 0.008820 0.116893 0.135458
5 0.009144 0.017969 0.126323
预测,生成submission

预测,生成submission

(10th place in the competition was 0.108)

test_preds=learn.get_preds(DatasetType.Test)
test_df["Sales"]=np.exp(test_preds[0].data).numpy().T[0]
test_df[["Id","Sales"]]=test_df[["Id","Sales"]].astype("int")
test_df[["Id","Sales"]].to_csv("rossmann_submission.csv",index=False)

Jeremy 在课程中是如何讲解学习率的

lesson 2

如何从图中读取最优学习率区间?

[quote=“Daniel, post:44, topic:39325”]

why do we need learning rate at all?

Lesson 3

How to pick learning rate carefully?

Lesson 5

What is fit-one-cycle
1 Like

第七课: 手写Resnets; U-net; Generative (adversarial) networks

Overview 综述

In the final lesson of Practical Deep Learning for Coders we’ll study one of the most important techniques in modern architectures: the skip connection. This is most famously used in the resnet, which is the architecture we’ve used throughout this course for image classification, and appears in many cutting edge results. We’ll also look at the U-net architecture, which uses a different type of skip connection to greatly improve segmentation results (and also for similar tasks where the output structure is similar to the input).

在这最后一节课里,我们将学到最新结构设计中最重要的一个技术:skip connection 。这项技术诞生于resnet, 也就是我们在做图片分类时一直在用的模型框架,为我们带来了顶级的表现。我们还会学习U-net结构,这项技术采用另一种skip connection,极大地改进了segmentation的效果(这项技术同样适用于其他任务,只要他们的输入值和输出值结构相似)。

We’ll then use the U-net architecture to train a super-resolution model. This is a model which can increase the resolution of a low-quality image. Our model won’t only increase resolution—it will also remove jpeg artifacts, and remove unwanted text watermarks.

之后我们将用U-net训练 super-resolution 模型。这个模型能够提升低像素图片的清晰度。我们的模型不仅可以提升像素,还能去除jpeg格式的杂物,以及消除文字水印。

In order to make our model produce high quality results, we will need to create a custom loss function which incorporates feature loss (also known as perceptual loss), along with gram loss. These techniques can be used for many other types of image generation task, such as image colorization.

为了让模型生成高质量输出,我们需要设计一款特制损失函数来将特征损失值(也就是所谓的perceptual loss)和gram 损失值做融合。这些技巧同样适用于很多其他的图片生成任务,比如图片上色。

Finally, we’ll learn about a recent loss function known as generative adversarial loss (used in generative adversarial networks, or GANs), which can improve the quality of generative models in some contexts, at the cost of speed.

最后,我们讲学习一个很新的损失函数,被称为generative adversarial loss (被用于生成对抗网络模型,也就是GANs),它能改进生成模型在某任务背景下的表现,但速度上会有所牺牲。

The techniques we show in this lesson include some unpublished research that:

  • Let us train GANs more quickly and reliably than standard approaches, by leveraging transfer learning
  • Combines architectural innovations and loss function approaches that haven’t been used in this way before.

The results are stunning, and train in just a couple of hours (compared to previous approaches that take a couple of days).

我们在本课中展示但还未正式做学术发表的技巧,如下:

  • 利用迁移学习,做到比常规方法更快更可靠的训练GANs
  • 在结构设计创新与损失函数使用方法的融合上,也做出了史无前例的创新

对比之前常规方法需要数天时间,我们只是训练了数小时,模型表现已经非常靓丽。

Lesson Resources 课程资源

Other Resources 其他资源


编辑此页面.

Hi @PegasusWithoutWinds

I will translate all the 7 lesson md files here. could you help me contribute to the official course-v3 repo without me doing the PR (which I found the process a bit tedious)? Is it possible?
thanks!

Lesson 6: Regularization; Convolutions; Data ethics

第六课:正则化,卷积,数据伦理

Overview 综述

Today we discuss some powerful techniques for improving training and avoiding over-fitting:

  • Dropout: remove activations at random during training in order to regularize the model
  • Data augmentation: modify model inputs during training in order to effectively increase data size
  • Batch normalization: adjust the parameterization of a model in order to make the loss surface smoother.

今天我们学习讨论一些帮助我们改进训练和避免过拟合的强大技巧:

  • Dropout: 随机去除一些激活层上的值,目的是对模型做正则处理
  • Data augmentation数据增强:对模型输入值做调整,目的是显著增加数据尺寸
  • Batch normalization批量正常化:规整模型参数值,目的是训练时让损失值变化更平滑

Next up, we’ll learn all about convolutions, which can be thought of as a variant of matrix multiplication with tied weights, and are the operation at the heart of modern computer vision models (and, increasingly, other types of models too).

接下来,我们会学习convolutions卷积,这个概念可以被理解为一种数组乘法与多个捆绑参数扫描器合作的变体,是当下机器视觉的核心算法(同时也在不断为其他类别的模型所使用)。

We’ll use this knowledge to create a class activated map, which is a heat-map that shows which parts of an image were most important in making a prediction.

我们将基于此创建一个类叫 activated map, 其功能是对图片做热力图处理,从而凸显展示图片中对预测最重要的部位。

Finally, we’ll cover a topic that many students have told us is the most interesting and surprising part of the course: data ethics. We’ll learn about some of the ways in which models can go wrong, with a particular focus on feedback loops, why they cause problems, and how to avoid them. We’ll also look at ways in which bias in data can lead to biased algorithms, and discuss questions that data scientists can and should be asking to help ensure that their work doesn’t lead to unexpected negative outcomes.

最后,我们将学习数据伦理, 许多学员认为这是一个非常有趣且出乎意料的课程内容。我们会了解到模型在什么情况下会出问题,会着重讲到feedback loops 反馈循环, 以及为什么这些会是问题,以及如何规避。我们还会看到数据中的偏差是如何导致算法偏差(歧视)的,还会探讨关于数据科学家能做什么,以及是否应该力争确保他们的工作不会导致意想不到的负面结果。

Lesson Resources 课程资源

Other Resources 其他资源


编辑此页面.

Lesson 5: Back propagation; Accelerated SGD; Neural net from scratch

第五课:反向传递,加速版随机梯度下降,手写神经网络

Overview 综述

In lesson 5 we put all the pieces of training together to understand exactly what is going on when we talk about back propagation. We’ll use this knowledge to create and train a simple neural network from scratch.

在本课中我们会深入训练环节细节来讲解什么是反向传递。在此基础上,我们会手写一个简单的神经网络

We’ll also see how we can look inside the weights of an embedding layer, to find out what our model has learned about our categorical variables. This will let us get some insights into which movies we should probably avoid at all costs…

我们还将深入观察embedding层的参数,看看模型学到了哪些关于类别变量的知识。这些知识将帮助我们识别那些需要权利回避的电影…

Although embeddings are most widely known in the context of word embeddings for NLP, they are at least as important for categorical variables in general, such as for tabular data or collaborative filtering. They can even be used with non-neural models with great success.

尽管embeddings的知名度在自然语言word embeddings领域里是最高的,但在广义的类别变量问题的背景下,如表格数据问题或者是推荐算法问题里,他们的重要性不容小觑。他们甚至在非神经网络模型里也有杰出表现。

Resources 资源

Lesson resources 课程资源

Other resources 其他资源


编辑此页面.

1 Like

Hey @Daniel, I could walk you through the PR process if you would like to. If you still find it too complicated, I can certainly submit the PR for you.

Lesson 1: Image classification

You can click the blue arrow buttons on the left and right panes to hide them and make more room for the video. You can search the transcript using the text box at the bottom. Scroll down this page for links to many useful resources. If you have any other suggestions for links, edits, or anything else, you’ll find an “edit” link at the bottom of this (and every) notes panel.

点击左侧和右侧的蓝色箭头按钮来隐藏panel给你更多观看视频的空间。你可以屏幕下方搜索字幕并进行视频时间跳跃。页面下方还有大量有用资源。如果你有任何建议,可以在最下方的“编辑”链接,增加你想添加的链接或编辑。

Overview 综述

To follow along with the lessons, you’ll need to connect to a cloud GPU provider which has the fastai library installed (recommended; it should take only 5 minutes or so, and cost under $0.50/hour), or set up a computer with a suitable GPU yourself (which can take days to get working if you’re not familiar with the process, so we don’t recommend it). You’ll also need to be familiar with the basics of the Jupyter Notebook environment we use for running deep learning experiments. Up to date tutorials and recommendations for these are available from the course website.

跟随课程,你需要有一个云端GPU能运行fastai(推荐,目前最便宜的是每小时0.5美元),或者在本地设置自己的GPU(非常费时费事,不推荐)。你需要熟悉Jupyter Notebook的使用环境来做深度学习实验。更多最新的GPU指南可以在课程官网中查看。

The key outcome of this lesson is that we’ll have trained an image classifier which can recognize pet breeds at state of the art accuracy. The key to this success is the use of transfer learning, which will be a key platform for much of this course. We’ll also see how to analyze the model to understand its failure modes. In this case, we’ll see that the places where the model is making mistakes is in the same areas that even breeding experts can make mistakes.

本课的核心目标是训练一个图片分类器,将宠物种类识别做到最专业级的精确度。实验成功的关键是迁移学习 transfer learning,也是本课程的核心平台或模型模版工具之一. 我们会学习如何分析模型以理解错误发生所在。在此过程中,我们将看到模型犯错的地方,就连宠物种类鉴定专家也会判断出错。

We’ll discuss the overall approach of the course, which is somewhat unusual in being top-down rather than bottom-up. So rather than starting with theory, and only getting to practical applications later, instead we start with practical applications, and then gradually dig deeper and deeper in to them, learning the theory as needed. This approach takes more work for teachers to develop, but it’s been shown to help students a lot, for example in education research at Harvard by David Perkins.

我们还将探讨本课程的授课模式,即自上而下,而非自下而上。也就是说,我们是从实验开始,根据需求,逐步深入学习理论,而非传统方式,讲完理论,才慢慢开始实践。这种方法对老师挑战较大非常耗时,但对学生受益颇丰,例如 education research at Harvard by David Perkins.

We also discuss how to set the most important hyper-parameter when training neural networks: the learning rate, using Leslie Smith’s fantastic learning rate finder method. Finally, we’ll look at the important but rarely discussed topic of labeling, and learn about some of the features that fastai provides for allowing you to easily add labels to your images.

我们还将讨论在训练模型时如何设置那些最重要的超参数hyper-parameter。我们将采用Leslie Smith’s fantastic learning rate finder method来设置学习率。最后,我们将研究很少讨论但非常重要的labeling数据标记, 并学习fastai 库提供的轻松添加图片标注的功能

If you want to more deeply understand how PyTorch really works, you may want to check out this official PyTorch tutorial by Jeremy—although we’d only suggest doing that once you’ve completed a few lessons.

如果你想要深入理解pytorch的实际工作,可以参看 this official PyTorch tutorial by Jeremy,但先别急,建议你在学完本课程的几节课后再学

Links 链接

Lesson resources 课程资源

Other resources 其他资源

How to scrape images 如何从网页爬取图片


编辑此页面

编辑此页面, 点击这里. 你会进入GitHub一个页面让你上交修改。它们会自动生成 pull request 然后经由管理员审核后发布。