[PYTHON] Prédiction de la moyenne Nikkei avec Pytorch 2

Merci. L'autre jour, j'ai promis d'aller à un bain public avec mes juniors, mais on m'a refusé, "Je suis désolé, j'ai raté le dernier train avec une fille ...", et le travail a progressé avec colère et l'article était terminé.

Donc, je l'ai présenté dans l'article précédent, Pytorch Prediction of Nikkei Average ~ Makuma ~.

Using Deep Learning Neural Networks and Candlestick Chart Representation to Predict Stock Market

J'ai créé, codé et appris l'ensemble de données pour, donc je vais le garder sous forme de mémorandum.

Création de l'ensemble de données

L'ensemble de données utilisé ici est comme un graphique, mais c'est un peu spécial. (Pour plus de détails, veuillez consulter le papier !!) Ce qui a été créé en référence à l'article 0000.png

De cette façon, l'image est de 48x48 et le haut et le bas sont représentés en rouge et vert. Ci-dessous le code.

candle_make.ipynb


#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import csv
import glob
import pandas as pd
import numpy as np
import sys
import matplotlib.pyplot as plt
import datetime
import openpyxl
 
#Représentation de pied de bougie
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
path = "/content/drive/My Drive/Colab/pytorch_pre/"
sys.path.append("/content/drive/My Drive/Colab/pytorch_pre")
import mpl_finance

Importation liée à la bibliothèque. Étant donné que google colaboratory est utilisé, le chemin, etc. indique l'emplacement où les fichiers sur le lecteur sont stockés. Le plus rare est peut-être mpl_finance. Il peut être téléchargé depuis le hub git. C'est un modèle pratique qui peut être utilisé pour représenter des pieds de bougie. mlp_finance

candle_make.ipynb


future_num = 1
fname = path + "data/nikkei_heikin_x3.csv"
flist = glob.glob(fname)
for file in flist:
  dt = pd.read_csv(file, header=0, encoding="utf-8_sig", index_col='Datetime')

dt = dt.sort_values('Datetime')
print(dt)

future_price = dt.iloc[future_num:-18]['le dernier prix'].values
curr_price = dt.iloc[:-18-future_num]['le dernier prix'].values
    
#future_Traitez le prix par rapport à num jours plus tard comme l'étiquette correcte
y_data_tmp = future_price / curr_price
#Préparez une liste pour l'étiquette de réponse correcte

y_data = np.zeros_like(y_data_tmp)
y_data_nam = np.zeros(len(y_data_tmp)+1, dtype=object)
Y_data = np.zeros((len(y_data_tmp)+1, 2), dtype=object)
Y_columns = ["label","ImageName"]

#Avenir à prévoir_Bonne réponse si le nombre de jours plus tard augmente
for i in range(len(y_data_tmp)):
    Y_data[i,0] = 0
    if y_data_tmp[i] >= 1.0:
        y_data[i] = 1
        Y_data[i,0] = 1
count = 0
for i in y_data:
  if i == 1:
    count += 1

print(count)
for i in range(1,len(y_data_tmp)+1):
    y_data_nam[i] = "{:04}.png ".format(i-1) 
    Y_data[i,1] = y_data_nam[i]
Y_data[0,0] = "label"
Y_data[0,1] = "ImageName"
dn = pd.DataFrame(Y_data)
dn.columns = Y_columns
np.savetxt(path+"debug/y_data.csv", dn, delimiter=",", fmt='%s') #Écrire dans un fichier csv

Je vais m'occuper de l'étiquetage ici. Les données lues sont organisées et binarisées par 1 si le prix du jour est supérieur à celui de la veille et 0 si le prix est inférieur à celui de la veille. Afin de pouvoir appeler l'étiquette à partir du nom de l'image plus tard, arrangez le nom de fichier (image name) et l'étiquette dans la même ligne dans csv et faites-le comme un tableau.

candle_make.ipynb


img_create = 1
if img_create == 1:
    seq_len = 20
    df = pd.read_csv(fname, parse_dates=True, index_col=0)
    df = df.sort_values('Datetime')
    df = df.rename(columns={'Prix ouvert':'Open','Prix élevé':'High','Bas prix':'Low','le dernier prix':'Close','Le volume':'Volume'})
    df.fillna(0)
    plt.style.use('dark_background')
    df.reset_index(inplace=True)
    df['Datetime'] = df['Datetime'].map(mdates.date2num)
    for i in range(0, len(df)):
        c = df.iloc[i:i + int(seq_len) - 1, :]
        if len(c) == int(seq_len-1):
            # Date,Open,High,Low,Adj Close,Volume
            ohlc = zip(c['Datetime'], c['Open'], c['High'],
                       c['Low'], c['Close'], c['Volume'])
            my_dpi = 96
            fig = plt.figure(figsize=(48 / my_dpi, 48 / my_dpi), dpi=my_dpi)
            ax1 = plt.subplot2grid((1, 1), (0, 0))
            # candlestick2_ohlc(ax1, c['Open'],c['High'],c['Low'],c['Close'], width=0.4, colorup='#77d879', colordown='#db3f3f')
            mpl_finance.candlestick_ohlc(ax1, ohlc, width=0.4,
                             colorup='#77d879', colordown='#db3f3f')
            ax1.grid(False)
            ax1.set_xticklabels([])
            ax1.set_yticklabels([])
            ax1.xaxis.set_visible(False)
            ax1.yaxis.set_visible(False)
            ax1.axis('off')
#            pngfile = 'datasets/{}_{}_{}.png'.format(
#                i, seq_len, fname[11:-4])
            pngfile = 'datasets/{:04}.png'.format(i)
            fig.savefig(path+pngfile,  pad_inches=0, transparent=False)
            plt.close(fig)
    print("Converting olhc to candlestik finished.")

C'est presque le même que le papier. L'affichage du volume n'est pas possible. Faites-moi savoir si vous le pouvez. Puisqu'il ne s'agit pas de la même forme de données numériques que le papier, il y a correspondance. Ce sont les données que j'ai utilisées.

スクリーンショット 2020-09-17 15.51.21.png

Faites correspondre la forme en renommant. Ceci complète l'image de l'ensemble de données.

Apprentissage

Le modèle de formation utilise ResNet. Dans l'article, SOTA a été enregistré en utilisant une structure de modèle unique, mais ResNet a également obtenu des résultats suffisants, donc je vais l'utiliser.

resnet.ipynb



class MyDataSet(Dataset):
    def __init__(self, csv_path, root_dir):
        self.train_df = pd.read_csv(csv_path)
        self.root_dir = root_dir
        self.images = os.listdir(self.root_dir)
        self.transform = transforms.Compose([transforms.ToTensor()])
        self.y_columns = ["label","ImageName"]
        
    def __len__(self):
        return len(self.images)
    
    def __getitem__(self, idx):
        #Chargement d'image
        # print(self.images)
        image_name = self.images[idx]
        image = Image.open(os.path.join(self.root_dir, image_name) )
        image = image.convert('RGB') # PyTorch 0.4 ou plus tard
        # label (0 or 1)
        self.train_df.columns = self.y_columns
        label = self.train_df.query('ImageName=="'+image_name+'"')['label'].iloc[0]
        return self.transform(image), int(label)

def conv3x3(in_channels, out_channels, stride=1, groups=1, dilation=1):
     return nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=stride,
                      padding=dilation, groups=groups, bias=True,
                      dilation=dilation)


def conv1x1(in_channels, out_channels, stride=1):
     return nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=stride, bias=True)


class BasicBlock(nn.Module):
 #  Implementation of Basic Building Block

    def __init__(self, in_channels, out_channels, stride=1, downsample=None):
     super(BasicBlock, self).__init__()
    
     self.conv1 = conv3x3(in_channels, out_channels, stride)
     self.bn1 = nn.BatchNorm2d(out_channels)
     self.relu = nn.ReLU(inplace=True)
     self.conv2 = conv3x3(out_channels, out_channels)
     self.bn2 = nn.BatchNorm2d(out_channels)
     self.downsample = downsample

    def forward(self, x):
     identity_x = x  # hold input for shortcut connection
    
     out = self.conv1(x)
     out = self.bn1(out)
     out = self.relu(out)
    
     out = self.conv2(out)
     out = self.bn2(out)
    
     if self.downsample is not None:
         identity_x = self.downsample(x)
    
     out += identity_x  # shortcut connection
     return self.relu(out)

class ResidualLayer(nn.Module):

     def __init__(self, num_blocks, in_channels, out_channels, block=BasicBlock):
         super(ResidualLayer, self).__init__()
         downsample = None
         if in_channels != out_channels:
             downsample = nn.Sequential(
                 conv1x1(in_channels, out_channels),
                 nn.BatchNorm2d(out_channels)
         )
         self.first_block = block(in_channels, out_channels, downsample=downsample)
         self.blocks = nn.ModuleList(block(out_channels, out_channels) for _ in range(num_blocks))

     def forward(self, x):
         out = self.first_block(x)
         for block in self.blocks:
             out = block(out)
         return out

class ResNet18(nn.Module):

   def __init__(self, num_classes):
       super(ResNet18, self).__init__()
       self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3)
       self.bn1 = nn.BatchNorm2d(64)
       self.relu = nn.ReLU(inplace=True)
       self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
       self.layer1 = ResidualLayer(2, in_channels=64, out_channels=64)
       self.layer2 = ResidualLayer(2, in_channels=64, out_channels=128)
       self.layer3 = ResidualLayer(
           2, in_channels=128, out_channels=256)
       self.layer4 = ResidualLayer(
           2, in_channels=256, out_channels=512)
       self.avg_pool = nn.AdaptiveAvgPool2d((1, 1))
       self.fc = nn.Linear(512, num_classes)

   def forward(self, x):
       out = self.conv1(x)
       out = self.bn1(out)
       out = self.relu(out)
       out = self.maxpool(out)

       out = self.layer1(out)
       out = self.layer2(out)
       out = self.layer3(out)
       out = self.layer4(out)

       out = self.avg_pool(out)
       out = out.view(out.size(0), -1)
       out = self.fc(out)

       return out
   
class Trainer:

    def __init__(self, model, optimizer, criterion):
        self.device = 'cuda' if torch.cuda.is_available() else 'cpu'
        self.model = model.to(self.device)
        self.optimizer = optimizer
        self.criterion = criterion

    def epoch_train(self, train_loader):
        self.model.train()
        epoch_loss = 0
        correct = 0
        total = 0

        for batch_idx, (inputs, targets) in enumerate(train_loader):
            inputs = inputs.to(self.device)
            targets = targets.to(self.device).long()

            self.optimizer.zero_grad()

            outputs = self.model(inputs)
            loss = self.criterion(outputs, targets)
            loss.backward()
            self.optimizer.step()

            epoch_loss += loss.item()
            _, predicted = torch.max(outputs.data, 1)
            total += targets.size(0)
            correct += predicted.eq(targets.data).cpu().sum().item()

        epoch_loss /= len(train_loader)
        acc = 100 * correct / total
        return epoch_loss, acc

    def epoch_valid(self, valid_loader):
        self.model.eval()
        epoch_loss = 0
        correct = 0
        total = 0

        for batch_idx, (inputs, targets) in enumerate(valid_loader):
            inputs = inputs.to(self.device)
            targets = targets.to(self.device).long()
            outputs = self.model(inputs)
            loss = self.criterion(outputs, targets)

            epoch_loss += loss.item()
            _, predicted = torch.max(outputs.data, 1)
            total += targets.size(0)
            correct += predicted.eq(targets.data).cpu().sum().item()

        epoch_loss /= len(valid_loader)
        acc = 100 * correct / total
        return epoch_loss, acc

    @property
    def params(self):
        return self.model.state_dict()

Définition ResNet, lecture de l'ensemble de données, etc. MyDataSet lit l'étiquette et le nom du fichier et les étiquette.

resnet.ipynb



if __name__ == '__main__':
    model = ResNet18(2)
    
    epoch_n = 100
    
    optimizer = optim.Adam(model.parameters(),
                        lr=0.001,
                        weight_decay=1e-4)
    
    criterion = nn.CrossEntropyLoss()

    trainer = Trainer(model, optimizer, criterion)

    transform = transforms.Compose([
        transforms.Resize((50, 50)),
        transforms.ToTensor(),
    ])

    tmp_data = MyDataSet(path+'debug/y_data.csv', path+'datasets/')
    dtrain, dtest = train_test_split(tmp_data, test_size=0.2)#Vous devez avoir 4 sorties??
    # x_train, y_train, x_test, y_test = train_test_split(tmp_data)
    
    train_loader = torch.utils.data.DataLoader(dtrain, batch_size=43, shuffle=True,
                              drop_last=True)
    valid_loader = torch.utils.data.DataLoader(dtest, batch_size=43, shuffle=True,
                              drop_last=True)
    best_acc = -1
    for epoch in range(1, 1 + epoch_n):
        train_loss, train_acc = trainer.epoch_train(train_loader)
        valid_loss, valid_acc = trainer.epoch_valid(valid_loader)

        if valid_acc > best_acc:
            best_acc = valid_acc
            best_params = trainer.params

        print(f'EPOCH: {epoch} / {epoch_n}')
        print(f'TRAIN LOSS: {train_loss:.3f}, TRAIN ACC: {train_acc:.3f}')
        print(f'VALID LOSS: {valid_loss:.3f}, VALID ACC: {valid_acc:.3f}')

    torch.save(best_params, path + 'models/resnet.pth')

C'est la partie à apprendre. Je pense que c'est presque la même chose qu'un ResNet normal. C'est un résultat d'apprentissage.

EPOCH: 1 / 100
TRAIN LOSS: 0.700, TRAIN ACC: 62.114
VALID LOSS: 1.145, VALID ACC: 52.442
EPOCH: 2 / 100
TRAIN LOSS: 0.502, TRAIN ACC: 76.391
VALID LOSS: 0.476, VALID ACC: 78.023
EPOCH: 3 / 100
TRAIN LOSS: 0.426, TRAIN ACC: 81.248
VALID LOSS: 0.467, VALID ACC: 77.907
EPOCH: 4 / 100
TRAIN LOSS: 0.368, TRAIN ACC: 83.633
VALID LOSS: 0.357, VALID ACC: 85.000
EPOCH: 5 / 100
TRAIN LOSS: 0.324, TRAIN ACC: 86.488
VALID LOSS: 0.648, VALID ACC: 76.395
EPOCH: 6 / 100
TRAIN LOSS: 0.305, TRAIN ACC: 87.018
VALID LOSS: 0.365, VALID ACC: 84.884
EPOCH: 7 / 100
TRAIN LOSS: 0.277, TRAIN ACC: 88.284
VALID LOSS: 0.480, VALID ACC: 79.884
.
.
.
EPOCH: 92 / 100
TRAIN LOSS: 0.006, TRAIN ACC: 99.853
VALID LOSS: 0.874, VALID ACC: 85.349
EPOCH: 93 / 100
TRAIN LOSS: 0.025, TRAIN ACC: 99.058
VALID LOSS: 0.960, VALID ACC: 78.953
EPOCH: 94 / 100
TRAIN LOSS: 0.028, TRAIN ACC: 99.058
VALID LOSS: 0.992, VALID ACC: 85.698
EPOCH: 95 / 100
TRAIN LOSS: 0.021, TRAIN ACC: 99.264
VALID LOSS: 0.744, VALID ACC: 84.884
EPOCH: 96 / 100
TRAIN LOSS: 0.007, TRAIN ACC: 99.735
VALID LOSS: 1.000, VALID ACC: 85.349
EPOCH: 97 / 100
TRAIN LOSS: 0.008, TRAIN ACC: 99.735
VALID LOSS: 0.834, VALID ACC: 86.279
EPOCH: 98 / 100
TRAIN LOSS: 0.020, TRAIN ACC: 99.470
VALID LOSS: 0.739, VALID ACC: 85.930
EPOCH: 99 / 100
TRAIN LOSS: 0.005, TRAIN ACC: 99.853
VALID LOSS: 0.846, VALID ACC: 86.395
EPOCH: 100 / 100
TRAIN LOSS: 0.016, TRAIN ACC: 99.382
VALID LOSS: 1.104, VALID ACC: 83.953

Nous avons enregistré 100% pour les données de train et 87% pour les données de test. Considérant environ 60% en utilisant le LSTM précédent, la précision est bien meilleure.

Considération de conclusion

Il s'avère que la précision peut être améliorée en frappant simplement le haut et le bas en utilisant l'image. Je ne sais pas s'il sera rentable de l'utiliser, mais ... Puisqu'il s'agit d'une expérience de suivi de l'article, je pense à intégrer l'apprentissage à distance et à prédire une augmentation de 3% d'ici.

En passant, sur les données d'environ 4300, seulement 70 ont augmenté de 3% par rapport à la veille. Il s'agit d'un ensemble de données assez déséquilibré, représentant 5% du total.

La prochaine fois, j'aimerais faire quelque chose à ce sujet.

Recommended Posts

Prédiction de la moyenne Nikkei avec Pytorch 2
Prédiction de la moyenne Nikkei avec Pytorch
Prédiction de la moyenne Nikkei avec Pytorch ~ Makuma ~
Prédiction de l'onde de péché avec keras
Prédiction des ondes de Sin (retour) avec Pytorch
4/22 prédiction de l'onde de péché avec keras
Classification multi-étiquette d'images multi-classes avec pytorch
Jouez avec PyTorch
Validation croisée avec PyTorch
À partir de PyTorch
Utilisez RTX 3090 avec PyTorch
Installer la diffusion de la torche avec PyTorch 1.7
[PyTorch] Un peu de compréhension de CrossEntropyLoss avec des formules mathématiques
Résumé des problèmes lors de la segmentation sémantique avec Pytorch
Préparation de l'environnement d'exécution de PyTorch avec Docker Novembre 2019
[PyTorch] Classification des images du CIFAR-10
Sauvegardez la sortie de GAN une par une ~ Avec l'implémentation de GAN par PyTorch ~
Essayez Auto Encoder avec Pytorch
Equation de mouvement avec sympy
Implémenter le GPU PyTorch + avec Docker
Démineur d'apprentissage automatique avec PyTorch
PyTorch avec AWS Lambda [importation Lambda]
Souvenirs de combats avec Selenium
Gratter la moyenne du Nikkei avec le dramaturge-python
Effectuer un fractionnement stratifié avec PyTorch
J'ai créé Word2Vec avec Pytorch
Prédiction de probabilité de données déséquilibrées
Calcul sans erreur avec le big.Float de Golang
Prédiction de séries chronologiques facile avec Prophet
Recherche en grille d'hyper paramètres avec Scikit-learn
Jugement de vacances, y compris les vacances avec bash
[Tutoriel PyTorch ⑤] Apprentissage de PyTorch avec des exemples (Partie 2)
Résumé de l'implémentation de base par PyTorch
Apprenez avec les réseaux convolutifs PyTorch Graph
Essayez de prédire les courses de chevaux avec Chainer
J'ai essayé d'implémenter Attention Seq2Seq avec PyTorch
Premiers pas avec Python Bases de Python
J'ai essayé d'implémenter DeepPose avec PyTorch
Jeu de vie avec Python! (Le jeu de la vie de Conway)
Automatisation des opérations à distance avec Fabric
10 fonctions du "langage avec batterie" python
Comment augmenter les données avec PyTorch
4ème nuit de boucle avec pour
Principes de base pour toucher MongoDB avec MongoEngine
[Tutoriel PyTorch ⑤] Apprentissage de PyTorch avec des exemples (Partie 1)
Traduction japonaise appropriée de pytorch tensor_tutorial
Implémentation de la méthode Dyxtra par python
Construction de l'environnement pytorch @ python3.8 avec pipenv
Coexistence de Python2 et 3 avec CircleCI (1.0)
Obtenez un rembourrage de réflexion Pytorch avec Tensorflow
Application de graphiques avec des curseurs
Etude de base d'OpenCV avec Python
Une collection de conseils pour accélérer l'apprentissage et le raisonnement avec PyTorch