!20821 提交GRU模型GPU版本PR,优化Ascend性能与精度,合并GPU/Ascend为同一套代码

Merge pull request !20821 from 吕昱峰(Nate.River)/gru
This commit is contained in:
i-robot 2021-08-04 11:26:51 +00:00 committed by Gitee
commit 59d8e30203
20 changed files with 944 additions and 202 deletions

View File

@ -46,7 +46,7 @@ In this model, we use the Multi30K dataset as our train and test dataset.As trai
# [Environment Requirements](#content)
- HardwareAscend
- HardwareAscend or GPU
- Prepare hardware environment with Ascend processor.
- Framework
- [MindSpore](https://gitee.com/mindspore/mindspore)
@ -81,15 +81,27 @@ nltk.download()
After dataset preparation, you can start training and evaluation as follows:
```bash
# run training example
cd ./scripts
bash run_standalone_train.sh [TRAIN_DATASET_PATH]
# download dataset
bash download_dataset.sh
# preprocess dataset
bash preprocess.sh [DATASET_PATH]
# create mindrecord
bash create_dataset.sh [DATASET_PATH] [DATASET_PATH]
# run training example
bash run_standalone_train_{platform}.sh [TRAIN_DATASET_PATH]
# run distributed training example
bash run_distribute_train_ascend.sh [RANK_TABLE_FILE] [TRAIN_DATASET_PATH]
bash run_distribute_train_{platform}.sh [RANK_TABLE_FILE] [TRAIN_DATASET_PATH]
# platform: ascend or gpu
# do not need [RANK_TABLE_FILE] if you use GPU
# run evaluation example
bash run_eval.sh [CKPT_FILE] [DATASET_PATH]
bash run_eval_{platform}.sh [CKPT_FILE] [DATASET_PATH]
# platform: ascend or gpu
```
- Running on ModelArts (If you want to run in modelarts, please check the official documentation of [modelarts](https://support.huaweicloud.com/modelarts/), and you can start training as follows)
@ -158,7 +170,6 @@ The GRU network script and code result are as follows:
│ ├──local_adapter.py // Local adapter
│ ├──moxing_adapter.py // Moxing adapter for ModelArts
├── src
| ├──gru.py // gru cell architecture.
│ ├──create_data.py // Dataset preparation.
│ ├──dataset.py // Dataset loader to feed into model.
│ ├──gru_for_infer.py // GRU eval model architecture.
@ -167,16 +178,24 @@ The GRU network script and code result are as follows:
│ ├──lr_schedule.py // Learning rate scheduler.
│ ├──parse_output.py // Parse output file.
│ ├──preprocess.py // Dataset preprocess.
| ├──rnn_cells.py // rnn cell architecture.
| ├──rnns.py // rnn layer architecture.
│ ├──seq2seq.py // Seq2seq architecture.
| ├──utils.py // utils for rnn.
│ ├──tokenization.py // tokenization for the dataset.
│ ├──weight_init.py // Initialize weights in the net.
├── scripts
│ ├──create_dataset.sh // shell script for create dataset.
│ ├──download_dataset.sh // shell script for download dataset.
│ ├──parse_output.sh // shell script for parse eval output file to calculate BLEU.
│ ├──preprocess.sh // shell script for preprocess dataset.
│ ├──run_distributed_train.sh // shell script for distributed train on ascend.
│ ├──run_eval.sh // shell script for standalone eval on ascend.
│ ├──run_standalone_train.sh // shell script for standalone eval on ascend.
│ ├──run_distributed_train_ascend.sh // shell script for distributed train on ascend.
│ ├──run_distributed_train_gpu.sh // shell script for distributed train on gpu.
│ ├──run_eval_ascend.sh // shell script for standalone eval on ascend.
│ ├──run_eval_gpu.sh // shell script for standalone eval on gpu.
│ ├──run_infer_310.sh // shell script for 310 inference.
│ ├──run_standalone_train_ascend.sh // shell script for standalone eval on ascend.
│ ├──run_standalone_train_gpu.sh // shell script for standalone eval on gpu.
├── default_config.yaml // Configurations
├── postprocess.py // GRU postprocess script.
├── preprocess.py // GRU preprocess script.
@ -188,7 +207,14 @@ The GRU network script and code result are as follows:
## [Dataset Preparation](#content)
Firstly, we should download the dataset from the WMT16 official net.After downloading the Multi30k dataset file, we get six dataset file, which is show as below.And we should in put the in same directory.
Firstly, we should download the dataset from the WMT16 official net.
```bash
cd scripts
bash download_dataset.sh
```
After downloading the Multi30k dataset file, we get six dataset file, which is show as below.And we should in put the in same directory.
```text
train.de
@ -250,14 +276,17 @@ Parameters for both training and evaluation can be set in config.py. All the dat
```bash
cd ./scripts
bash run_standalone_train.sh [DATASET_PATH]
bash run_standalone_train_{platform}.sh [DATASET_PATH]
# platform: ascend or gpu
```
- Running scripts for distributed training of GRU. Task training on multiple device and run the following command in bash to be executed in `scripts/`:
``` bash
cd ./scripts
bash run_distributed_train.sh [RANK_TABLE_PATH] [DATASET_PATH]
bash run_distributed_train_{platform}.sh [RANK_TABLE_PATH] [DATASET_PATH]
# platform: ascend or gpu
# do not need [RANK_TABLE_FILE] if you use GPU
```
## [Inference Process](#content)
@ -266,7 +295,8 @@ Parameters for both training and evaluation can be set in config.py. All the dat
``` bash
cd ./scripts
bash run_eval.sh [CKPT_FILE] [DATASET_PATH]
bash run_eval_{platform}.sh [CKPT_FILE] [DATASET_PATH]
# platform: ascend or gpu
```
- After evalulation, we will get eval/target.txt and eval/output.txt.Then we can use scripts/parse_output.sh to get the translation.
@ -354,35 +384,35 @@ perl multi-bleu.perl target.txt.forbleu < output.txt.forbleu
### Training Performance
| Parameters | Ascend |
| -------------------------- | -------------------------------------------------------------- |
| Resource | Ascend 910; OS Euler2.8 |
| uploaded Date | 01/18/2021 (month/day/year) |
| MindSpore Version | 1.1.0 |
| Dataset | Multi30k Dataset |
| Training Parameters | epoch=30, batch_size=16 |
| Optimizer | Adam |
| Loss Function | NLLLoss |
| outputs | probability |
| Speed | 50ms/step (1pcs) |
| Epoch Time | 13.4s (1pcs) |
| Loss | 2.5984 |
| Params (M) | 21 |
| Checkpoint for inference | 272M (.ckpt file) |
| Scripts | [gru](https://gitee.com/mindspore/mindspore/tree/master/model_zoo/official/nlp/gru) |
| Parameters | Ascend | GPU |
| -------------------------- | ----------------------------- |---------------------------|
| Resource | Ascend 910; OS Euler2.8 | GTX1080Ti, Ubuntu 18.04 |
| uploaded Date | 06/05/2021 (month/day/year) | 06/05/2021 (month/day/year) |
| MindSpore Version | 1.2.0 |1.2.0 |
| Dataset | Multi30k Dataset | Multi30k Dataset |
| Training Parameters | epoch=30, batch_size=16 | epoch=30, batch_size=16 |
| Optimizer | Adam | Adam |
| Loss Function | NLLLoss | NLLLoss |
| outputs | probability | probability |
| Speed | 35ms/step (1pcs) | 200ms/step (1pcs) |
| Epoch Time | 64.4s (1pcs) | 361.5s (1pcs) |
| Loss | 3.86888 |2.533958 |
| Params (M) | 21 | 21 |
| Checkpoint for inference | 272M (.ckpt file) | 272M (.ckpt file) |
| Scripts | [gru](https://gitee.com/mindspore/mindspore/tree/master/model_zoo/official/nlp/gru) |[gru](https://gitee.com/mindspore/mindspore/tree/master/model_zoo/official/nlp/gru) |
### Inference Performance
| Parameters | Ascend |
| ------------------- | --------------------------- |
| Resource | Ascend 910; OS Euler2.8 |
| Uploaded Date | 01/18/2020 (month/day/year) |
| MindSpore Version | 1.1.0 |
| Dataset | Multi30K |
| batch_size | 1 |
| outputs | label index |
| Accuracy | BLEU: 30.30 |
| Model for inference | 272M (.ckpt file) |
| Parameters | Ascend | GPU |
| ------------------- | --------------------------- |---------------------------|
| Resource | Ascend 910; OS Euler2.8 | GTX1080Ti, Ubuntu 18.04 |
| Uploaded Date | 06/05/2021 (month/day/year) | 06/05/2021 (month/day/year)|
| MindSpore Version | 1.2.0 | 1.2.0 |
| Dataset | Multi30K | Multi30K |
| batch_size | 1 | 1 |
| outputs | label index | label index |
| Accuracy | BLEU: 31.26 | BLEU: 29.30 |
| Model for inference | 272M (.ckpt file) | 272M (.ckpt file) |
# [Random Situation Description](#content)

View File

@ -36,6 +36,8 @@ scale_factor: 2
scale_window: 2000
warmup_ratio: 0.333333
teacher_force_ratio: 0.5
compute_type: mstype.float16
dtype: mstype.float32
run_distribute: False
dataset_path: ""

View File

@ -20,6 +20,8 @@ import ast
import argparse
from pprint import pformat
import yaml
import mindspore.common.dtype as mstype
class Config:
"""
@ -108,6 +110,24 @@ def merge(args, cfg):
cfg[item] = args_var[item]
return cfg
def parse_dtype(dtype):
if dtype not in ["mstype.float32", "mstype.float16"]:
raise ValueError("Not supported dtype")
if dtype == "mstype.float32":
return mstype.float32
if dtype == "mstype.float16":
return mstype.float16
return None
def extra_operations(cfg):
"""
Do extra work on config
Args:
config: Object after instantiation of class 'Config'.
"""
cfg.dtype = parse_dtype(cfg.dtype)
cfg.compute_type = parse_dtype(cfg.compute_type)
def get_config():
"""
@ -121,6 +141,8 @@ def get_config():
default, helper, choices = parse_yaml(path_args.config_path)
args = parse_cli_to_yaml(parser=parser, cfg=default, helper=helper, choices=choices, cfg_path=path_args.config_path)
final_config = merge(args, default)
return Config(final_config)
final_config = Config(final_config)
extra_operations(final_config)
return final_config
config = get_config()

View File

@ -1,3 +0,0 @@
nltk
numpy
pyyaml

View File

@ -17,7 +17,6 @@ echo "==========================================================================
echo "Please run the script as: "
echo "sh create_dataset.sh DATASET_PATH OUTPUT_PATH"
echo "for example: sh create_dataset.sh /path/multi30k/ /path/multi30k/mindrecord/"
echo "DATASET_NAME including ag, dbpedia, and yelp_p"
echo "It is better to use absolute path."
echo "=============================================================================================================="
ulimit -u unlimited

View File

@ -0,0 +1,33 @@
#!/bin/bash
# Copyright 2021 Huawei Technologies Co., Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ============================================================================
CUR_PATH=`pwd`
DATA_PATH=${CUR_PATH}/../data
TRAIN_URL=http://www.quest.dcs.shef.ac.uk/wmt16_files_mmt/training.tar.gz
VALID_URL=http://www.quest.dcs.shef.ac.uk/wmt16_files_mmt/validation.tar.gz
TEST_URL=http://www.quest.dcs.shef.ac.uk/wmt16_files_mmt/mmt16_task1_test.tar.gz
mkdir ${DATA_PATH}
cd ${DATA_PATH}
wget --no-check-certificate ${TRAIN_URL}
wget --no-check-certificate ${VALID_URL}
wget --no-check-certificate ${TEST_URL}
tar xvf training.tar.gz
tar xvf validation.tar.gz
tar xvf mmt16_task1_test.tar.gz
/bin/rm training.tar.gz
/bin/rm validation.tar.gz
/bin/rm mmt16_task1_test.tar.gz

View File

@ -47,6 +47,7 @@ exit 1
fi
ulimit -u unlimited
export DEVICE_TARGET="Ascend"
export DEVICE_NUM=8
export RANK_SIZE=8
export RANK_TABLE_FILE=$PATH1
@ -65,6 +66,6 @@ do
cd ./train_parallel$i || exit
echo "start training for rank $RANK_ID, device $DEVICE_ID"
env > env.log
python train.py --run_distribute=True --dataset_path=$DATASET_PATH &> log &
python train.py --device_target=$DEVICE_TARGET --run_distribute=True --dataset_path=$DATASET_PATH &> log &
cd ..
done
done

View File

@ -0,0 +1,54 @@
#!/bin/bash
# Copyright 2021 Huawei Technologies Co., Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ============================================================================
if [ $# -ne 1 ]
then
echo "Usage: sh run_distribute_train_gpu.sh [DATASET_PATH]"
exit 1
fi
get_real_path(){
if [ "${1:0:1}" == "/" ]; then
echo "$1"
else
echo "$(realpath -m $PWD/$1)"
fi
}
DATASET_PATH=$(get_real_path $1)
echo $DATASET_PATH
if [ ! -f $DATASET_PATH ]
then
echo "error: DATASET_PATH=$DATASET_PATH is not a file"
exit 1
fi
ulimit -u unlimited
export DEVICE_TARGET="GPU"
export DEVICE_NUM=8
rm -rf ./train
mkdir ./train
cp ../*.py ./train
cp ../*.yaml ./train
cp *.sh ./train
cp -r ../src ./train
cp -r ../model_utils ./train
cd ./train || exit
echo "start training for $DEVICE_NUM GPUs"
env > env.log
mpirun --allow-run-as-root -n $DEVICE_NUM python train.py --run_distribute=True --device_target=$DEVICE_TARGET --dataset_path=$DATASET_PATH &> log &
cd ..

View File

@ -0,0 +1,62 @@
#!/bin/bash
# Copyright 2021 Huawei Technologies Co., Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ============================================================================
if [ $# -ne 2 ]
then
echo "Usage: sh run_eval_ascend.sh [CKPT_FILE] [DATASET_PATH]"
exit 1
fi
ulimit -u unlimited
export DEVICE_NUM=1
export DEVICE_ID=0
export RANK_ID=0
export RANK_SIZE=1
export DEVICE_TARGET="Ascend"
get_real_path(){
if [ "${1:0:1}" == "/" ]; then
echo "$1"
else
echo "$(realpath -m $PWD/$1)"
fi
}
CKPT_FILE=$(get_real_path $1)
echo $CKPT_FILE
if [ ! -f $CKPT_FILE ]
then
echo "error: CKPT_FILE=$CKPT_FILE is not a file"
exit 1
fi
DATASET_PATH=$(get_real_path $2)
echo $DATASET_PATH
if [ ! -f $DATASET_PATH ]
then
echo "error: DATASET_PATH=$DATASET_PATH is not a file"
exit 1
fi
rm -rf ./eval
mkdir ./eval
cp ../*.py ./eval
cp ../*.yaml ./eval
cp *.sh ./eval
cp -r ../src ./eval
cp -r ../model_utils ./eval
cd ./eval || exit
echo "start eval for device $DEVICE_ID"
env > env.log
python eval.py --device_target=$DEVICE_TARGET --ckpt_file=$CKPT_FILE --dataset_path=$DATASET_PATH &> log &
cd ..

View File

@ -15,7 +15,7 @@
# ============================================================================
if [ $# -ne 2 ]
then
echo "Usage: sh run_eval.sh [CKPT_FILE] [DATASET_PATH]"
echo "Usage: sh run_eval_gpu.sh [CKPT_FILE] [DATASET_PATH]"
exit 1
fi
ulimit -u unlimited
@ -23,6 +23,8 @@ export DEVICE_NUM=1
export DEVICE_ID=0
export RANK_ID=0
export RANK_SIZE=1
export DEVICE_TARGET="GPU"
get_real_path(){
if [ "${1:0:1}" == "/" ]; then
echo "$1"
@ -56,5 +58,5 @@ cp -r ../model_utils ./eval
cd ./eval || exit
echo "start eval for device $DEVICE_ID"
env > env.log
python eval.py --ckpt_file=$CKPT_FILE --dataset_path=$DATASET_PATH &> log &
python eval.py --device_target=$DEVICE_TARGET --ckpt_file=$CKPT_FILE --dataset_path=$DATASET_PATH &> log &
cd ..

View File

@ -0,0 +1,54 @@
#!/bin/bash
# Copyright 2021 Huawei Technologies Co., Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ============================================================================
if [ $# -ne 1 ]
then
echo "Usage: sh run_standalone_train_ascend.sh [DATASET_PATH]"
exit 1
fi
ulimit -u unlimited
export DEVICE_NUM=1
export DEVICE_ID=0
export RANK_ID=0
export RANK_SIZE=1
export DEVICE_TARGET="Ascend"
get_real_path(){
if [ "${1:0:1}" == "/" ]; then
echo "$1"
else
echo "$(realpath -m $PWD/$1)"
fi
}
DATASET_PATH=$(get_real_path $1)
echo $DATASET_PATH
if [ ! -f $DATASET_PATH ]
then
echo "error: DATASET_PATH=$DATASET_PATH is not a file"
exit 1
fi
rm -rf ./train
mkdir ./train
cp ../*.py ./train
cp ../*.yaml ./train
cp *.sh ./train
cp -r ../src ./train
cp -r ../model_utils ./train
cd ./train || exit
echo "start training for device $DEVICE_ID"
env > env.log
python train.py --device_target=$DEVICE_TARGET --dataset_path=$DATASET_PATH &> log &
cd ..

View File

@ -15,14 +15,15 @@
# ============================================================================
if [ $# -ne 1 ]
then
echo "Usage: sh run_distribute_train_ascend.sh [DATASET_PATH]"
echo "Usage: sh run_standalone_train_gpu.sh [DATASET_PATH]"
exit 1
fi
ulimit -u unlimited
export DEVICE_NUM=1
export DEVICE_ID=4
export DEVICE_ID=0
export RANK_ID=0
export RANK_SIZE=1
export DEVICE_TARGET="GPU"
get_real_path(){
if [ "${1:0:1}" == "/" ]; then
echo "$1"
@ -38,7 +39,6 @@ then
echo "error: DATASET_PATH=$DATASET_PATH is not a file"
exit 1
fi
rm -rf ./train
mkdir ./train
cp ../*.py ./train
@ -49,5 +49,5 @@ cp -r ../model_utils ./train
cd ./train || exit
echo "start training for device $DEVICE_ID"
env > env.log
python train.py --dataset_path=$DATASET_PATH &> log &
python train.py --device_target=$DEVICE_TARGET --dataset_path=$DATASET_PATH &> log &
cd ..

View File

@ -1,104 +0,0 @@
# Copyright 2021 Huawei Technologies Co., Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ============================================================================
"""GRU cell"""
import mindspore.nn as nn
import mindspore.ops.operations as P
import mindspore.common.dtype as mstype
from src.weight_init import gru_default_state
class BidirectionGRU(nn.Cell):
'''
BidirectionGRU model
Args:
config: config of network
'''
def __init__(self, config, is_training=True):
super(BidirectionGRU, self).__init__()
if is_training:
self.batch_size = config.batch_size
else:
self.batch_size = config.eval_batch_size
self.embedding_size = config.encoder_embedding_size
self.hidden_size = config.hidden_size
self.weight_i, self.weight_h, self.bias_i, self.bias_h, self.init_h = gru_default_state(self.batch_size,
self.embedding_size,
self.hidden_size)
self.weight_bw_i, self.weight_bw_h, self.bias_bw_i, self.bias_bw_h, self.init_bw_h = \
gru_default_state(self.batch_size, self.embedding_size, self.hidden_size)
self.reverse = P.ReverseV2(axis=[1])
self.concat = P.Concat(axis=2)
self.squeeze = P.Squeeze(axis=0)
self.rnn = P.DynamicGRUV2()
self.text_len = config.max_length
self.cast = P.Cast()
def construct(self, x):
'''
BidirectionGRU construction
Args:
x(Tensor): BidirectionGRU input
Returns:
output(Tensor): rnn output
hidden(Tensor): hidden state
'''
x = self.cast(x, mstype.float16)
y1, _, _, _, _, _ = self.rnn(x, self.weight_i, self.weight_h, self.bias_i, self.bias_h, None, self.init_h)
bw_x = self.reverse(x)
y1_bw, _, _, _, _, _ = self.rnn(bw_x, self.weight_bw_i,
self.weight_bw_h, self.bias_bw_i, self.bias_bw_h, None, self.init_bw_h)
y1_bw = self.reverse(y1_bw)
output = self.concat((y1, y1_bw))
hidden = self.concat((y1[self.text_len-1:self.text_len:1, ::, ::],
y1_bw[self.text_len-1:self.text_len:1, ::, ::]))
hidden = self.squeeze(hidden)
return output, hidden
class GRU(nn.Cell):
'''
GRU model
Args:
config: config of network
'''
def __init__(self, config, is_training=True):
super(GRU, self).__init__()
if is_training:
self.batch_size = config.batch_size
else:
self.batch_size = config.eval_batch_size
self.embedding_size = config.encoder_embedding_size
self.hidden_size = config.hidden_size
self.weight_i, self.weight_h, self.bias_i, self.bias_h, self.init_h = \
gru_default_state(self.batch_size, self.embedding_size + self.hidden_size*2, self.hidden_size)
self.rnn = P.DynamicGRUV2()
self.cast = P.Cast()
def construct(self, x):
'''
GRU construction
Args:
x(Tensor): GRU input
Returns:
output(Tensor): rnn output
hidden(Tensor): hidden state
'''
x = self.cast(x, mstype.float16)
y1, h1, _, _, _, _ = self.rnn(x, self.weight_i, self.weight_h, self.bias_i, self.bias_h, None, self.init_h)
return y1, h1

View File

@ -240,3 +240,48 @@ class GRUTrainOneStepWithLossScaleCell(nn.Cell):
succ = self.optimizer(grads)
ret = (loss, cond, scaling_sens)
return F.depend(ret, succ)
class GRUTrainOneStepCell(nn.TrainOneStepCell):
"""
Encapsulation class of GRU network training.
Append an optimizer to the training network after that the construct
function can be called to create the backward graph.
Args:
network (Cell): The training network. Note that loss function should have been added.
optimizer (Optimizer): Optimizer for updating the weights.
sens (Number): The adjust parameter. Default: 1.0.
enable_clip_grad (boolean): If True, clip gradients in GRUTrainOneStepCell. Default: True.
"""
def __init__(self, network, optimizer, sens=1.0, enable_clip_grad=True):
super(GRUTrainOneStepCell, self).__init__(network, optimizer, sens)
self.cast = P.Cast()
self.hyper_map = C.HyperMap()
self.clip_gradients = ClipGradients()
self.enable_clip_grad = enable_clip_grad
def set_sens(self, value):
self.sens = value
def construct(self,
encoder_inputs,
decoder_inputs,
teacher_force,
sens=None):
"""Defines the computation performed."""
weights = self.weights
loss = self.network(encoder_inputs,
decoder_inputs,
teacher_force)
grads = self.grad(self.network, weights)(encoder_inputs,
decoder_inputs,
teacher_force,
self.cast(F.tuple_to_array((self.sens,)),
mstype.float32))
if self.enable_clip_grad:
grads = self.clip_gradients(grads, GRADIENT_CLIP_TYPE, GRADIENT_CLIP_VALUE)
grads = self.grad_reducer(grads)
succ = self.optimizer(grads)
return F.depend(loss, succ)

View File

@ -0,0 +1,130 @@
# Copyright 2021 Huawei Technologies Co., Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ============================================================================
'''RNN Cells module, include RNNCell, GRUCell, LSTMCell'''
import math
import numpy as np
import mindspore.nn as nn
import mindspore.ops as P
from mindspore import Tensor, Parameter
from mindspore.common.initializer import initializer, Uniform
def rnn_tanh_cell(inputs, hidden, w_ih, w_hh, b_ih, b_hh):
'''RNN cell function with tanh activation'''
if b_ih is None:
igates = P.MatMul(False, True)(inputs, w_ih)
hgates = P.MatMul(False, True)(hidden, w_hh)
else:
igates = P.MatMul(False, True)(inputs, w_ih) + b_ih
hgates = P.MatMul(False, True)(hidden, w_hh) + b_hh
return P.Tanh()(igates + hgates)
def rnn_relu_cell(inputs, hidden, w_ih, w_hh, b_ih, b_hh):
'''RNN cell function with relu activation'''
if b_ih is None:
igates = P.MatMul(False, True)(inputs, w_ih)
hgates = P.MatMul(False, True)(hidden, w_hh)
else:
igates = P.MatMul(False, True)(inputs, w_ih) + b_ih
hgates = P.MatMul(False, True)(hidden, w_hh) + b_hh
return P.ReLU()(igates + hgates)
def lstm_cell(inputs, hidden, w_ih, w_hh, b_ih, b_hh):
'''LSTM cell function'''
hx, cx = hidden
if b_ih is None:
gates = P.MatMul(False, True)(inputs, w_ih) + P.MatMul(False, True)(hx, w_hh)
else:
gates = P.MatMul(False, True)(inputs, w_ih) + P.MatMul(False, True)(hx, w_hh) + b_ih + b_hh
ingate, forgetgate, cellgate, outgate = P.Split(1, 4)(gates)
ingate = P.Sigmoid()(ingate)
forgetgate = P.Sigmoid()(forgetgate)
cellgate = P.Tanh()(cellgate)
outgate = P.Sigmoid()(outgate)
cy = (forgetgate * cx) + (ingate * cellgate)
hy = outgate * P.Tanh()(cy)
return hy, cy
def gru_cell(inputs, hidden, w_ih, w_hh, b_ih, b_hh):
'''GRU cell function'''
if b_ih is None:
gi = P.MatMul(False, True)(inputs, w_ih)
gh = P.MatMul(False, True)(hidden, w_hh)
else:
gi = P.MatMul(False, True)(inputs, w_ih) + b_ih
gh = P.MatMul(False, True)(hidden, w_hh) + b_hh
i_r, i_i, i_n = P.Split(1, 3)(gi)
h_r, h_i, h_n = P.Split(1, 3)(gh)
resetgate = P.Sigmoid()(i_r + h_r)
inputgate = P.Sigmoid()(i_i + h_i)
newgate = P.Tanh()(i_n + resetgate * h_n)
hy = newgate + inputgate * (hidden - newgate)
return hy
class RNNCellBase(nn.Cell):
'''Basic class for RNN Cells'''
def __init__(self, input_size: int, hidden_size: int, bias: bool, num_chunks: int):
super().__init__()
self.input_size = input_size
self.hidden_size = hidden_size
self.bias = bias
self.weight_ih = Parameter(Tensor(np.random.randn(num_chunks * hidden_size, input_size).astype(np.float32)))
self.weight_hh = Parameter(Tensor(np.random.randn(num_chunks * hidden_size, hidden_size).astype(np.float32)))
if bias:
self.bias_ih = Parameter(Tensor(np.random.randn(num_chunks * hidden_size).astype(np.float32)))
self.bias_hh = Parameter(Tensor(np.random.randn(num_chunks * hidden_size).astype(np.float32)))
self.reset_parameters()
def reset_parameters(self):
stdv = 1 / math.sqrt(self.hidden_size)
for weight in self.get_parameters():
weight.set_data(initializer(Uniform(stdv), weight.shape))
class RNNCell(RNNCellBase):
'''RNNCell operator class'''
_non_linearity = ['tanh', 'relu']
def __init__(self, input_size: int, hidden_size: int, bias: bool = True, nonlinearity: str = "tanh"):
super().__init__(input_size, hidden_size, bias, num_chunks=1)
if nonlinearity not in self._non_linearity:
raise ValueError("Unknown nonlinearity: {}".format(nonlinearity))
self.nonlinearity = nonlinearity
def construct(self, inputs, hx):
if self.nonlinearity == "tanh":
ret = rnn_tanh_cell(inputs, hx, self.weight_ih, self.weight_hh, self.bias_ih, self.bias_hh)
else:
ret = rnn_relu_cell(inputs, hx, self.weight_ih, self.weight_hh, self.bias_ih, self.bias_hh)
return ret
class LSTMCell(RNNCellBase):
'''LSTMCell operator class'''
def __init__(self, input_size: int, hidden_size: int, bias: bool = True):
super().__init__(input_size, hidden_size, bias, num_chunks=4)
self.support_non_tensor_inputs = True
def construct(self, inputs, hx):
return lstm_cell(inputs, hx, self.weight_ih, self.weight_hh, self.bias_ih, self.bias_hh)
class GRUCell(RNNCellBase):
'''GRUCell operator class'''
def __init__(self, input_size: int, hidden_size: int, bias: bool = True):
super().__init__(input_size, hidden_size, bias, num_chunks=3)
def construct(self, inputs, hx):
return gru_cell(inputs, hx, self.weight_ih, self.weight_hh, self.bias_ih, self.bias_hh)

View File

@ -0,0 +1,311 @@
# Copyright 2021 Huawei Technologies Co., Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ============================================================================
'''RNN operators module, include RNN, GRU, LSTM'''
import math
import numpy as np
import mindspore
import mindspore.nn as nn
import mindspore.ops as P
from mindspore.ops.primitive import constexpr
from mindspore import Tensor, Parameter, ParameterTuple
from mindspore import log as logger
from mindspore import context
from src.rnn_cells import rnn_relu_cell, rnn_tanh_cell, lstm_cell, gru_cell
from src.utils import Reverse, ReverseSequence
@constexpr
def _init_state(shape, dtype, is_lstm):
hx = Tensor(np.zeros(shape), dtype)
cx = Tensor(np.zeros(shape), dtype)
if is_lstm:
return (hx, cx)
return hx
class DynamicRNN(nn.Cell):
'''Dynamic RNN module to compute RNN cell by timesteps'''
def __init__(self, mode):
super().__init__()
if mode == "RNN_RELU":
cell = rnn_relu_cell
elif mode == "RNN_TANH":
cell = rnn_tanh_cell
elif mode == "LSTM":
cell = lstm_cell
elif mode == "GRU":
cell = gru_cell
else:
raise ValueError("Unrecognized RNN mode: " + mode)
self.cell = cell
self.is_lstm = mode == "LSTM"
def recurrent(self, x, h_0, w_ih, w_hh, b_ih, b_hh):
'''recurrent steps without sequence length'''
time_step = x.shape[0]
outputs = []
t = 0
h = h_0
while t < time_step:
x_t = x[t:t+1:1]
x_t = P.Squeeze(0)(x_t)
h = self.cell(x_t, h, w_ih, w_hh, b_ih, b_hh)
if self.is_lstm:
outputs.append(h[0])
else:
outputs.append(h)
t += 1
outputs = P.Stack()(outputs)
return outputs, h
def variable_recurrent(self, x, h, seq_length, w_ih, w_hh, b_ih, b_hh):
'''recurrent steps with sequence length'''
time_step = x.shape[0]
h_t = h
if self.is_lstm:
hidden_size = h[0].shape[-1]
zero_output = P.ZerosLike()(h_t[0])
else:
hidden_size = h.shape[-1]
zero_output = P.ZerosLike()(h_t)
seq_length = P.Cast()(seq_length, mindspore.float32)
seq_length = P.BroadcastTo((hidden_size, -1))(seq_length)
seq_length = P.Cast()(seq_length, mindspore.int32)
seq_length = P.Transpose()(seq_length, (1, 0))
outputs = []
state_t = h_t
t = 0
while t < time_step:
x_t = x[t:t+1:1]
x_t = P.Squeeze(0)(x_t)
h_t = self.cell(x_t, state_t, w_ih, w_hh, b_ih, b_hh)
seq_cond = seq_length > t
if self.is_lstm:
state_t_0 = P.Select()(seq_cond, h_t[0], state_t[0])
state_t_1 = P.Select()(seq_cond, h_t[1], state_t[1])
output = P.Select()(seq_cond, h_t[0], zero_output)
state_t = (state_t_0, state_t_1)
else:
state_t = P.Select()(seq_cond, h_t, state_t)
output = P.Select()(seq_cond, h_t, zero_output)
outputs.append(output)
t += 1
outputs = P.Stack()(outputs)
return outputs, state_t
def construct(self, x, h, seq_length, w_ih, w_hh, b_ih, b_hh):
if seq_length is None:
return self.recurrent(x, h, w_ih, w_hh, b_ih, b_hh)
return self.variable_recurrent(x, h, seq_length, w_ih, w_hh, b_ih, b_hh)
class RNNBase(nn.Cell):
'''Basic class for RNN operators'''
def __init__(self, mode, input_size, hidden_size, num_layers=1, has_bias=True,
batch_first=False, dropout=0, bidirectional=False):
super().__init__()
if not 0 <= dropout <= 1:
raise ValueError("dropout should be a number in range [0, 1] "
"representing the probability of an element being "
"zeroed")
if dropout > 0 and num_layers == 1:
logger.warning("dropout option adds dropout after all but last "
"recurrent layer, so non-zero dropout expects "
"num_layers greater than 1, but got dropout={} and "
"num_layers={}".format(dropout, num_layers))
if mode == "LSTM":
gate_size = 4 * hidden_size
elif mode == "GRU":
gate_size = 3 * hidden_size
elif mode == "RNN_TANH":
gate_size = hidden_size
elif mode == "RNN_RELU":
gate_size = hidden_size
else:
raise ValueError("Unrecognized RNN mode: " + mode)
self.is_ascend = context.get_context("device_target") == "Ascend"
if self.is_ascend:
self.reverse = P.ReverseV2([0])
self.reverse_sequence = P.ReverseSequence(0, 1)
else:
self.reverse = Reverse(0)
self.reverse_sequence = ReverseSequence(0, 1)
self.hidden_size = hidden_size
self.batch_first = batch_first
self.num_layers = num_layers
self.dropout = dropout
self.dropout_op = nn.Dropout(float(1 - dropout))
self.bidirectional = bidirectional
self.has_bias = has_bias
self.rnn = DynamicRNN(mode)
num_directions = 2 if bidirectional else 1
self.is_lstm = mode == "LSTM"
self.w_ih_list = []
self.w_hh_list = []
self.b_ih_list = []
self.b_hh_list = []
stdv = 1 / math.sqrt(self.hidden_size)
for layer in range(num_layers):
for direction in range(num_directions):
layer_input_size = input_size if layer == 0 else hidden_size * num_directions
suffix = '_reverse' if direction == 1 else ''
self.w_ih_list.append(Parameter(
Tensor(np.random.uniform(-stdv, stdv, (gate_size, layer_input_size)).astype(np.float32)),
name='weight_ih_l{}{}'.format(layer, suffix)))
self.w_hh_list.append(Parameter(
Tensor(np.random.uniform(-stdv, stdv, (gate_size, hidden_size)).astype(np.float32)),
name='weight_hh_l{}{}'.format(layer, suffix)))
if has_bias:
self.b_ih_list.append(Parameter(
Tensor(np.random.uniform(-stdv, stdv, (gate_size)).astype(np.float32)),
name='bias_ih_l{}{}'.format(layer, suffix)))
self.b_hh_list.append(Parameter(
Tensor(np.random.uniform(-stdv, stdv, (gate_size)).astype(np.float32)),
name='bias_hh_l{}{}'.format(layer, suffix)))
self.w_ih_list = ParameterTuple(self.w_ih_list)
self.w_hh_list = ParameterTuple(self.w_hh_list)
self.b_ih_list = ParameterTuple(self.b_ih_list)
self.b_hh_list = ParameterTuple(self.b_hh_list)
def _stacked_bi_dynamic_rnn(self, x, h, seq_length):
"""stacked bidirectional dynamic_rnn"""
pre_layer = x
h_n = ()
c_n = ()
output = 0
for i in range(self.num_layers):
offset = i * 2
if self.has_bias:
w_f_ih, w_f_hh, b_f_ih, b_f_hh = \
self.w_ih_list[offset], self.w_hh_list[offset], \
self.b_ih_list[offset], self.b_hh_list[offset]
w_b_ih, w_b_hh, b_b_ih, b_b_hh = \
self.w_ih_list[offset + 1], self.w_hh_list[offset + 1], \
self.b_ih_list[offset + 1], self.b_hh_list[offset + 1]
else:
w_f_ih, w_f_hh = self.w_ih_list[offset], self.w_hh_list[offset]
w_b_ih, w_b_hh = self.w_ih_list[offset + 1], self.w_hh_list[offset + 1]
b_f_ih, b_f_hh, b_b_ih, b_b_hh = None, None, None, None
if self.is_lstm:
h_f_i = (h[0][offset], h[1][offset])
h_b_i = (h[0][offset + 1], h[1][offset + 1])
else:
h_f_i = h[offset]
h_b_i = h[offset + 1]
if seq_length is None:
x_b = self.reverse(pre_layer)
else:
x_b = self.reverse_sequence(pre_layer, seq_length)
output_f, h_t_f = self.rnn(pre_layer, h_f_i, seq_length, w_f_ih, w_f_hh, b_f_ih, b_f_hh)
output_b, h_t_b = self.rnn(x_b, h_b_i, seq_length, w_b_ih, w_b_hh, b_b_ih, b_b_hh)
if seq_length is None:
output_b = self.reverse(output_b)
else:
output_b = self.reverse_sequence(output_b, seq_length)
output = P.Concat(2)((output_f, output_b))
pre_layer = self.dropout_op(output) if (self.dropout != 0 and i < self.num_layers - 1) else output
if self.is_lstm:
h_n += (h_t_f[0], h_t_b[0],)
c_n += (h_t_f[1], h_t_b[1],)
else:
h_n += (h_t_f, h_t_b,)
if self.is_lstm:
h_n = P.Concat(0)(h_n)
c_n = P.Concat(0)(c_n)
h_n = h_n.view(h[0].shape)
c_n = c_n.view(h[1].shape)
return output, (h_n.view(h[0].shape), c_n.view(h[1].shape))
h_n = P.Concat(0)(h_n)
return output, h_n.view(h.shape)
def _stacked_dynamic_rnn(self, x, h, seq_length):
"""stacked mutil_layer dynamic_rnn"""
pre_layer = x
h_n = ()
c_n = ()
output = 0
for i in range(self.num_layers):
if self.has_bias:
w_ih, w_hh, b_ih, b_hh = self.w_ih_list[i], self.w_hh_list[i], self.b_ih_list[i], self.b_hh_list[i]
else:
w_ih, w_hh = self.w_ih_list[i], self.w_hh_list[i]
b_ih, b_hh = None, None
if self.is_lstm:
h_i = (h[0][i], h[1][i])
else:
h_i = h[i]
output, h_t = self.rnn(pre_layer, h_i, seq_length, w_ih, w_hh, b_ih, b_hh)
pre_layer = self.dropout_op(output) if (self.dropout != 0 and i < self.num_layers - 1) else output
if self.is_lstm:
h_n += (h_t[0],)
c_n += (h_t[1],)
else:
h_n += (h_t,)
if self.is_lstm:
h_n = P.Concat(0)(h_n)
c_n = P.Concat(0)(c_n)
h_n = h_n.view(h[0].shape)
c_n = c_n.view(h[1].shape)
return output, (h_n.view(h[0].shape), c_n.view(h[1].shape))
h_n = P.Concat(0)(h_n)
return output, h_n.view(h.shape)
def construct(self, x, h=None, seq_length=None):
'''Defines the RNN like operators performed'''
max_batch_size = x.shape[0] if self.batch_first else x.shape[1]
num_directions = 2 if self.bidirectional else 1
if h is None:
h = _init_state((self.num_layers * num_directions, max_batch_size, self.hidden_size), x.dtype, self.is_lstm)
if self.batch_first:
x = P.Transpose()(x, (1, 0, 2))
if self.bidirectional:
x, h = self._stacked_bi_dynamic_rnn(x, h, seq_length)
else:
x, h = self._stacked_dynamic_rnn(x, h, seq_length)
if self.batch_first:
x = P.Transpose()(x, (1, 0, 2))
return x, h
class RNN(RNNBase):
'''RNN operator class'''
def __init__(self, *args, **kwargs):
if 'nonlinearity' in kwargs:
if kwargs['nonlinearity'] == 'tanh':
mode = 'RNN_TANH'
elif kwargs['nonlinearity'] == 'relu':
mode = 'RNN_RELU'
else:
raise ValueError("Unknown nonlinearity '{}'".format(
kwargs['nonlinearity']))
del kwargs['nonlinearity']
else:
mode = 'RNN_TANH'
super(RNN, self).__init__(mode, *args, **kwargs)
class GRU(RNNBase):
'''GRU operator class'''
def __init__(self, *args, **kwargs):
mode = 'GRU'
super(GRU, self).__init__(mode, *args, **kwargs)
class LSTM(RNNBase):
'''LSTM operator class'''
def __init__(self, *args, **kwargs):
mode = 'LSTM'
super(LSTM, self).__init__(mode, *args, **kwargs)
self.support_non_tensor_inputs = True

View File

@ -18,8 +18,8 @@ from mindspore import Tensor
import mindspore.nn as nn
import mindspore.ops.operations as P
import mindspore.common.dtype as mstype
from src.gru import BidirectionGRU, GRU
from src.weight_init import dense_default_state
from src.rnns import GRU
class Attention(nn.Cell):
'''
@ -29,8 +29,8 @@ class Attention(nn.Cell):
super(Attention, self).__init__()
self.text_len = config.max_length
self.attn = nn.Dense(in_channels=config.hidden_size * 3,
out_channels=config.hidden_size).to_float(mstype.float16)
self.fc = nn.Dense(config.hidden_size, 1, has_bias=False).to_float(mstype.float16)
out_channels=config.hidden_size).to_float(config.compute_type)
self.fc = nn.Dense(config.hidden_size, 1, has_bias=False).to_float(config.compute_type)
self.expandims = P.ExpandDims()
self.tanh = P.Tanh()
self.softmax = P.Softmax()
@ -39,6 +39,9 @@ class Attention(nn.Cell):
self.concat = P.Concat(axis=2)
self.squeeze = P.Squeeze(axis=2)
self.cast = P.Cast()
self.dtype = config.dtype
self.compute_type = config.compute_type
def construct(self, hidden, encoder_outputs):
'''
Attention construction
@ -58,9 +61,9 @@ class Attention(nn.Cell):
energy = self.tanh(out)
attention = self.fc(energy)
attention = self.squeeze(attention)
attention = self.cast(attention, mstype.float32)
attention = self.cast(attention, self.dtype)
attention = self.softmax(attention)
attention = self.cast(attention, mstype.float16)
attention = self.cast(attention, self.compute_type)
return attention
class Encoder(nn.Cell):
@ -76,8 +79,9 @@ class Encoder(nn.Cell):
self.vocab_size = config.src_vocab_size
self.embedding_size = config.encoder_embedding_size
self.embedding = nn.Embedding(self.vocab_size, self.embedding_size)
self.rnn = BidirectionGRU(config, is_training=is_training).to_float(mstype.float16)
self.fc = nn.Dense(2*self.hidden_size, self.hidden_size).to_float(mstype.float16)
self.rnn = GRU(input_size=self.embedding_size, \
hidden_size=self.hidden_size, bidirectional=True).to_float(config.compute_type)
self.fc = nn.Dense(2*self.hidden_size, self.hidden_size).to_float(config.compute_type)
self.shape = P.Shape()
self.transpose = P.Transpose()
self.p = P.Print()
@ -85,6 +89,8 @@ class Encoder(nn.Cell):
self.text_len = config.max_length
self.squeeze = P.Squeeze(axis=0)
self.tanh = P.Tanh()
self.concat = P.Concat(2)
self.dtype = config.dtype
def construct(self, src):
'''
@ -99,8 +105,10 @@ class Encoder(nn.Cell):
'''
embedded = self.embedding(src)
embedded = self.transpose(embedded, (1, 0, 2))
embedded = self.cast(embedded, mstype.float16)
embedded = self.cast(embedded, self.dtype)
output, hidden = self.rnn(embedded)
hidden = self.transpose(hidden, (1, 0, 2))
hidden = hidden.view(hidden.shape[0], -1)
hidden = self.fc(hidden)
hidden = self.tanh(hidden)
return output, hidden
@ -118,7 +126,8 @@ class Decoder(nn.Cell):
self.vocab_size = config.trg_vocab_size
self.embedding_size = config.decoder_embedding_size
self.embedding = nn.Embedding(self.vocab_size, self.embedding_size)
self.rnn = GRU(config, is_training=is_training).to_float(mstype.float16)
self.rnn = GRU(input_size=self.embedding_size + self.hidden_size*2, \
hidden_size=self.hidden_size).to_float(config.compute_type)
self.text_len = config.max_length
self.shape = P.Shape()
self.transpose = P.Transpose()
@ -130,11 +139,13 @@ class Decoder(nn.Cell):
self.log_softmax = P.LogSoftmax(axis=1)
weight, bias = dense_default_state(self.embedding_size+self.hidden_size*3, self.vocab_size)
self.fc = nn.Dense(self.embedding_size+self.hidden_size*3, self.vocab_size,
weight_init=weight, bias_init=bias).to_float(mstype.float16)
weight_init=weight, bias_init=bias).to_float(config.compute_type)
self.attention = Attention(config)
self.bmm = P.BatchMatMul()
self.dropout = nn.Dropout(0.7)
self.expandims = P.ExpandDims()
self.dtype = config.dtype
def construct(self, inputs, hidden, encoder_outputs):
'''
Decoder construction
@ -150,21 +161,22 @@ class Decoder(nn.Cell):
'''
embedded = self.embedding(inputs)
embedded = self.transpose(embedded, (1, 0, 2))
embedded = self.cast(embedded, mstype.float16)
embedded = self.cast(embedded, self.dtype)
attn = self.attention(hidden, encoder_outputs)
attn = self.expandims(attn, 1)
encoder_outputs = self.transpose(encoder_outputs, (1, 0, 2))
weight = self.bmm(attn, encoder_outputs)
weight = self.transpose(weight, (1, 0, 2))
weight = self.cast(weight, self.dtype)
emd_con = self.concat((embedded, weight))
output, hidden = self.rnn(emd_con)
output = self.cast(output, self.dtype)
out = self.concat((embedded, output, weight))
out = self.squeeze(out)
hidden = self.squeeze(hidden)
prediction = self.fc(out)
prediction = self.dropout(prediction)
prediction = self.cast(prediction, mstype.float32)
prediction = self.cast(prediction, mstype.float32)
prediction = self.cast(prediction, self.dtype)
pred_prob = self.log_softmax(prediction)
pred_prob = self.expandims(pred_prob, 0)
return pred_prob, hidden

View File

@ -0,0 +1,76 @@
# Copyright 2021 Huawei Technologies Co., Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ============================================================================
'''Utils for GPU version GRU, like Reverse operators'''
import mindspore
import mindspore.nn as nn
import mindspore.ops as ops
import mindspore.numpy as np
class Reverse(nn.Cell):
"""Reverse operator, like Reverse in mindspore"""
def __init__(self, dim):
super().__init__()
self.dim = dim
def construct(self, input_x):
shape = input_x.shape
dim_size = shape[self.dim]
reversed_indexes = np.arange(dim_size-1, -1, -1)
output = ops.Gather()(input_x, reversed_indexes, self.dim)
return output
class ReverseSequence(nn.Cell):
"""Reverse sequence operator, like ReverseSequenceV2 in mindspore"""
def __init__(self, seq_dim, batch_dim=0):
super().__init__()
self.seq_dim = seq_dim
self.batch_dim = batch_dim
def construct(self, x, seq_lengths):
"""Defines the ReverseSequence operator computation performed."""
batch_size = x.shape[self.batch_dim]
max_seq_len = x.shape[self.seq_dim]
seq_lens_type = seq_lengths.dtype
back = ops.Sub()(seq_lengths, ops.OnesLike()(seq_lengths))
batch_idx = self.make_shape((batch_size, max_seq_len), seq_lens_type, 0)
forward_idx = self.make_shape((batch_size, max_seq_len), seq_lens_type, 1)
back = back.view(-1, 1)
reverse_idx = ops.Sub()(back, forward_idx)
condition = ops.Less()(reverse_idx, ops.ZerosLike()(reverse_idx))
reverse_idx = ops.Select()(condition, forward_idx, reverse_idx)
reverse_idx = ops.ExpandDims()(reverse_idx, 2)
batch_idx = ops.ExpandDims()(batch_idx, 2)
if self.batch_dim > self.seq_dim:
batch_idx = ops.Transpose()(batch_idx, (1, 0, 2))
reverse_idx = ops.Transpose()(reverse_idx, (1, 0, 2))
x = ops.Transpose()(x, (1, 0, 2))
start_indices = ops.Concat(2)((batch_idx, reverse_idx))
output = ops.GatherNd()(x, start_indices)
return output
def make_shape(self, shape, dtype, range_dim):
output = ops.Ones()(shape, mindspore.float32)
output = ops.CumSum()(output, range_dim)
output = ops.Cast()(output, dtype)
output = output - 1
return output

View File

@ -15,21 +15,7 @@
"""weight init"""
import math
import numpy as np
from mindspore import Tensor, Parameter
def gru_default_state(batch_size, input_size, hidden_size, num_layers=1, bidirectional=False):
'''Weight init for gru cell'''
stdv = 1 / math.sqrt(hidden_size)
weight_i = Parameter(Tensor(
np.random.uniform(-stdv, stdv, (input_size, 3*hidden_size)).astype(np.float32)), name='weight_i')
weight_h = Parameter(Tensor(
np.random.uniform(-stdv, stdv, (hidden_size, 3*hidden_size)).astype(np.float32)), name='weight_h')
bias_i = Parameter(Tensor(
np.random.uniform(-stdv, stdv, (3*hidden_size)).astype(np.float32)), name='bias_i')
bias_h = Parameter(Tensor(
np.random.uniform(-stdv, stdv, (3*hidden_size)).astype(np.float32)), name='bias_h')
init_h = Tensor(np.zeros((batch_size, hidden_size)).astype(np.float16))
return weight_i, weight_h, bias_i, bias_h, init_h
from mindspore import Tensor
def dense_default_state(in_channel, out_channel):
'''Weight init for dense cell'''

View File

@ -15,17 +15,19 @@
"""train script"""
import os
import time
import mindspore.common.dtype as mstype
from mindspore.context import ParallelMode
from mindspore import context
from mindspore.communication.management import init
from mindspore.communication.management import init, get_rank
from mindspore.train.callback import Callback, CheckpointConfig, ModelCheckpoint, TimeMonitor
from mindspore.train import Model
from mindspore.common import set_seed
from mindspore.train.loss_scale_manager import DynamicLossScaleManager
from mindspore.nn.optim import Adam
from mindspore import log as logger
from src.seq2seq import Seq2Seq
from src.gru_for_train import GRUWithLossCell, GRUTrainOneStepWithLossScaleCell
from src.gru_for_train import GRUWithLossCell, GRUTrainOneStepWithLossScaleCell, GRUTrainOneStepCell
from src.dataset import create_gru_dataset
from src.lr_schedule import dynamic_lr
@ -72,13 +74,20 @@ class LossCallBack(Callback):
cb_params.cur_step_num,
str(cb_params.net_outputs)))
with open("./loss_{}.log".format(self.rank_id), "a+") as f:
f.write("time: {}, epoch: {}, step: {}, loss: {}, overflow: {}, loss_scale: {}".format(
time_stamp_current - time_stamp_first,
cb_params.cur_epoch_num,
cb_params.cur_step_num,
str(cb_params.net_outputs[0].asnumpy()),
str(cb_params.net_outputs[1].asnumpy()),
str(cb_params.net_outputs[2].asnumpy())))
if context.get_context("device_target") == "Ascend":
f.write("time: {}, epoch: {}, step: {}, loss: {}, overflow: {}, loss_scale: {}".format(
time_stamp_current - time_stamp_first,
cb_params.cur_epoch_num,
cb_params.cur_step_num,
str(cb_params.net_outputs[0].asnumpy()),
str(cb_params.net_outputs[1].asnumpy()),
str(cb_params.net_outputs[2].asnumpy())))
else:
f.write("time: {}, epoch: {}, step: {}, loss: {}".format(
time_stamp_current - time_stamp_first,
cb_params.cur_epoch_num,
cb_params.cur_step_num,
str(cb_params.net_outputs.asnumpy())))
f.write('\n')
@ -139,13 +148,32 @@ def modelarts_pre_process():
@moxing_wrapper(pre_process=modelarts_pre_process)
def run_train():
"""run train."""
context.set_context(mode=context.GRAPH_MODE, device_target="Ascend", device_id=get_device_id(), save_graphs=False)
rank = get_rank_id()
context.set_context(mode=context.GRAPH_MODE, device_target=config.device_target,
device_id=get_device_id(), save_graphs=False)
if config.device_target == "GPU":
if config.compute_type != mstype.float32:
logger.warning('GPU only support fp32 temporarily, run with fp32.')
config.compute_type = mstype.float32
device_num = get_device_num()
if config.run_distribute:
context.set_auto_parallel_context(device_num=device_num, parallel_mode=ParallelMode.DATA_PARALLEL,
gradients_mean=True)
init()
if config.device_target == "Ascend":
rank = get_rank_id()
context.set_auto_parallel_context(device_num=device_num,
parallel_mode=ParallelMode.DATA_PARALLEL,
gradients_mean=True)
init()
elif config.device_target == "GPU":
rank = get_rank()
init("nccl")
context.set_auto_parallel_context(parallel_mode=ParallelMode.DATA_PARALLEL,
gradients_mean=True)
else:
raise ValueError(config.device_target)
else:
rank = 0
device_num = 1
mindrecord_file = config.dataset_path
if not os.path.exists(mindrecord_file):
print("dataset file {} not exists, please check!".format(mindrecord_file))
@ -162,8 +190,10 @@ def run_train():
scale_factor=config.scale_factor,
scale_window=config.scale_window)
update_cell = scale_manager.get_update_cell()
netwithgrads = GRUTrainOneStepWithLossScaleCell(network, opt, update_cell)
if config.device_target == "Ascend":
netwithgrads = GRUTrainOneStepWithLossScaleCell(network, opt, update_cell)
else:
netwithgrads = GRUTrainOneStepCell(network, opt)
time_cb = TimeMonitor(data_size=dataset_size)
loss_cb = LossCallBack(rank_id=rank)
cb = [time_cb, loss_cb]
@ -171,10 +201,10 @@ def run_train():
if config.save_checkpoint:
ckpt_config = CheckpointConfig(save_checkpoint_steps=config.ckpt_epoch * dataset_size,
keep_checkpoint_max=config.keep_checkpoint_max)
save_ckpt_path = os.path.join(config.outputs_dir, 'ckpt_' + str(get_rank_id()) + '/')
save_ckpt_path = os.path.join(config.outputs_dir, 'ckpt_' + str(rank) + '/')
ckpt_cb = ModelCheckpoint(config=ckpt_config,
directory=save_ckpt_path,
prefix='{}'.format(get_rank_id()))
prefix='{}'.format(rank))
cb += [ckpt_cb]
netwithgrads.set_train(True)
model = Model(netwithgrads)