Skip to content
This repository was archived by the owner on Aug 25, 2024. It is now read-only.

Commit 9f286de

Browse files
model: pytorch: Add custom Neural Network & layer support and loss function entrypoints
Fixes: #794
1 parent 04f017a commit 9f286de

29 files changed

+1205
-143
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
66

77
## [Unreleased]
88
### Added
9+
- CLI and Python example usage of Custom Neural Network
10+
- PyTorch loss function entrypoint style loading
11+
- Custom Neural Network, last layer support for pre-trained models
912
- Example usage of sklearn operations
1013
- Example Flower17 species image classification
1114
- Configloading ablity from CLI using "@" before filename

docs/tutorials/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,4 @@ or operations.
1313
operations
1414
sources/index
1515
dataflows/index
16+
neuralnetwork

docs/tutorials/neuralnetwork.rst

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
Custom Neural Network Tutorial
2+
==============================
3+
4+
Rock Paper Scissors Hand Pose Classification
5+
--------------------------------------------
6+
7+
This tutorial will show you how to train and test a PyTorch based custom neural network model made using DFFML.
8+
The dataset we will be using is the `rock-paper-scissors-dataset <http://www.laurencemoroney.com/rock-paper-scissors-dataset/>`_
9+
which contains images of hands in Rock/Paper/Scissors poses, each image is a 300x300 RGB image.
10+
11+
The model we'll be using is :ref:`PyTorchNeuralNetwork <plugin_model_dffml_model_pytorch_pytorchnet>`
12+
which is a part of ``dffml-model-pytorch``, a DFFML plugin which allows you to use PyTorch
13+
via DFFML. We can install it with ``pip``. We will also be using image loading from
14+
``dffml-config-image`` and YAML file loading from ``dffml-config-yaml`` for creating our neural network.
15+
16+
.. code-block:: console
17+
18+
$ pip install -U dffml-model-pytorch dffml-config-image dffml-config-yaml
19+
20+
Download the dataset and verify with with ``sha384sum``.
21+
22+
.. literalinclude:: /../examples/rockpaperscissors/dataset.sh
23+
24+
.. code-block:: console
25+
26+
rps.zip: OK
27+
rps-test-set.zip: OK
28+
rps-validation.zip: OK
29+
30+
Extract the datasets.
31+
32+
.. code-block:: console
33+
34+
$ unzip rps.zip
35+
$ unzip rps-test-set.zip
36+
$ unzip rps-validation.zip -d rps-predict
37+
38+
The dataset for training the model will be in the `rps` directory.
39+
The dataset for testing the model will be in the `rps-test-set` directory.
40+
The images we will be using for prediction on the neural network will be in the `rps-predict` directory.
41+
42+
Now that we have our dataset ready, we can perform classification of the hand poses to predict whether
43+
it is rock, paper or scissors!
44+
45+
We first create the neural network.
46+
47+
The neural network can be created in 2 ways using DFFML:
48+
1. By creating a dictionary of layers in YAML or JSON format passing the file via CLI (eg. @model.yaml).
49+
2. By using the torch module to create the model and passing an instance of the network to the model config.
50+
51+
52+
Command Line
53+
------------
54+
55+
We first create a YAML file to define the neural network with all the information about the layers along with
56+
the forward method which is passed as list of layers under the model name key:
57+
58+
**model.yaml**
59+
60+
.. literalinclude:: /../examples/rockpaperscissors/model.yaml
61+
62+
.. seealso::
63+
Sequential layers can also be created by indenting the layers under a key!
64+
The layers definied inside the Sequential layer can be used again while defining the forward method in the
65+
following syntax: `- key1.layer2`
66+
67+
.. Note::
68+
If the forward method is not given in the YAML file, forward method is automatically created by appending
69+
the top level layers sequentially.
70+
71+
Train the model.
72+
73+
.. literalinclude:: /../examples/rockpaperscissors/train.sh
74+
75+
.. code-block:: console
76+
77+
INFO:dffml.PyTorchNeuralNetworkContext:Training complete in 1m 42s
78+
INFO:dffml.PyTorchNeuralNetworkContext:Best Validation Accuracy: 1.000000
79+
80+
Assess the model's accuracy.
81+
82+
.. literalinclude:: /../examples/rockpaperscissors/accuracy.sh
83+
84+
The output is:
85+
86+
.. code-block:: console
87+
88+
0.8763440860215054
89+
90+
Predict with the trained model.
91+
92+
.. literalinclude:: /../examples/rockpaperscissors/predict.sh
93+
94+
Some of the Predictions:
95+
96+
.. literalinclude:: /../examples/rockpaperscissors/output.txt
97+
98+
99+
Python API
100+
----------
101+
102+
.. literalinclude:: /../examples/rockpaperscissors/python_example.py
103+
104+
The output will be as follows:
105+
106+
.. literalinclude:: /../examples/rockpaperscissors/python_output.txt
107+
108+
The model predicts the hand poses correctly with great confidence!

docs/usage/flower17/flower17_pytorch.rst

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ FLOWER17 Species classification using Transfer Learning
44
The model we'll be using is :ref:`AlexNet CNN Model <plugin_model_dffml_model_pytorch_alexnet>`
55
which is a part of ``dffml-model-pytorch``, a DFFML plugin which allows you to use PyTorch
66
via DFFML. We can install it with ``pip``. We will also be using image loading from
7-
``dffml-config-image``.
7+
``dffml-config-image`` and YAML file loading from ``dffml-config-yaml``.
88

99
.. code-block:: console
1010
11-
$ pip install -U dffml-model-pytorch dffml-config-image
11+
$ pip install -U dffml-model-pytorch dffml-config-yaml dffml-config-image
1212
1313
There are 2 ways to perform Transfer Learning:
1414

@@ -23,6 +23,10 @@ There are 2 ways to perform Transfer Learning:
2323

2424
In this example, we will be fine-tuning the AlexNet model. (We set `trainable=True`)
2525

26+
We first create a YAML file to define the last layer(s) to replace from the network architecture:
27+
28+
.. literalinclude:: /../examples/flower17/pytorch-alexnet/layers.yaml
29+
2630
Train the model.
2731

2832
.. literalinclude:: /../examples/flower17/pytorch-alexnet/train.sh

examples/flower17/pytorch-alexnet/accuracy.sh

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
11
dffml accuracy \
22
-model alexnet \
3+
-model-add_layers \
4+
-model-layers @layers.yaml \
35
-model-clstype str \
46
-model-classifications \
57
crocus windflower fritillary tulip pansy dandelion tigerlily sunflower \
68
bluebell cowslip coltsfoot snowdrop daffodil lilyvalley iris buttercup daisy \
79
-model-directory alexnet_model \
810
-model-imageSize 224 \
11+
-model-trainable \
912
-model-enableGPU \
13+
-model-normalize_mean 0.485 0.456 0.406 \
14+
-model-normalize_std 0.229 0.224 0.225 \
1015
-model-features image:int:$((500*500)) \
1116
-model-predict label:str:1 \
1217
-sources f=dir \
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
linear1:
2+
name: Linear
3+
in_features: 4096
4+
out_features: 256
5+
relu:
6+
name: ReLU
7+
dropout:
8+
name: Dropout
9+
p: 0.2
10+
linear2:
11+
name: Linear
12+
in_features: 256
13+
out_features: 17
14+
logsoftmax:
15+
name: LogSoftmax
16+
dim: 1

examples/flower17/pytorch-alexnet/predict.sh

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
11
dffml predict all \
22
-model alexnet \
3+
-model-add_layers \
4+
-model-layers @layers.yaml \
35
-model-clstype str \
46
-model-classifications \
57
crocus windflower fritillary tulip pansy dandelion tigerlily sunflower \
68
bluebell cowslip coltsfoot snowdrop daffodil lilyvalley iris buttercup daisy \
79
-model-directory alexnet_model \
810
-model-imageSize 224 \
11+
-model-trainable \
912
-model-enableGPU \
13+
-model-normalize_mean 0.485 0.456 0.406 \
14+
-model-normalize_std 0.229 0.224 0.225 \
1015
-model-features image:int:$((500*500)) \
1116
-model-predict label:str:1 \
1217
-sources f=csv \

examples/flower17/pytorch-alexnet/train.sh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
dffml train \
22
-model alexnet \
3+
-model-add_layers \
4+
-model-layers @layers.yaml \
35
-model-clstype str \
46
-model-classifications \
57
crocus windflower fritillary tulip pansy dandelion tigerlily sunflower \
@@ -11,6 +13,8 @@ dffml train \
1113
-model-validation_split 0.2 \
1214
-model-trainable \
1315
-model-enableGPU \
16+
-model-normalize_mean 0.485 0.456 0.406 \
17+
-model-normalize_std 0.229 0.224 0.225 \
1418
-model-features image:int:$((500*500)) \
1519
-model-predict label:str:1 \
1620
-sources f=dir \

examples/flower17/test_flower17.py

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,20 @@ async def test_shell_sklearn(self):
6262

6363
async def test_shell_pytorch(self):
6464
with directory_with_data_files() as tempdir:
65-
# Run training
66-
subprocess.check_output(
67-
["bash", sh_filepath("pytorch-alexnet/train.sh")]
65+
shutil.copy(
66+
sh_filepath("pytorch-alexnet/layers.yaml"),
67+
os.path.join(os.getcwd(), "layers.yaml"),
6868
)
69+
70+
# Run training
71+
with open(sh_filepath("pytorch-alexnet/train.sh"), "r") as cmd:
72+
cmd = cmd.read()
73+
cmd = cmd.replace("\n", "")
74+
cmd = cmd.replace("\\", "")
75+
cmd = shlex.split(cmd)
76+
cmd[cmd.index("-model-epochs") + 1] = "1"
77+
await CLI.cli(*cmd[1:])
78+
6979
# Check the Accuracy
7080
stdout = subprocess.check_output(
7181
["bash", sh_filepath("pytorch-alexnet/accuracy.sh")]
@@ -79,8 +89,7 @@ async def test_shell_pytorch(self):
7989
cmd = cmd.replace("\\", "")
8090
cmd = shlex.split(cmd)
8191
# When passing to CLI, remove first argument(dffml) and -pretty at the end
82-
cmd = cmd[1:-1]
83-
records = await CLI.cli(*cmd)
92+
records = await CLI.cli(*cmd[1:-1])
8493

8594
# Check the label for 1 record
8695
self.assertIsInstance(
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
dffml accuracy \
2+
-model pytorchnet \
3+
-model-features image:int:$((300*300*3)) \
4+
-model-clstype str \
5+
-model-classifications rock paper scissors \
6+
-model-predict label:int:1 \
7+
-model-network @model.yaml \
8+
-model-directory rps_model \
9+
-model-imageSize 150 \
10+
-model-enableGPU \
11+
-sources f=dir \
12+
-source-foldername rps-test-set \
13+
-source-feature image \
14+
-source-labels rock paper scissors

0 commit comments

Comments
 (0)