{ "cells": [ { "cell_type": "markdown", "metadata": { "id": "nwaAZRu1NTiI" }, "source": [ "# Q-learning \n", "\n", "#### This version implements q-learning using a custom enviroment \n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "DDf1gLC2NTiK" }, "outputs": [ { "ename": "", "evalue": "", "output_type": "error", "traceback": [ "\u001b[1;31mFailed to start the Kernel. \n", "Cannot execute code, session has been disposed. \n", "View Jupyter log for further details." ] } ], "source": [ "# !pip install -r ./requirements.txt\n", "# !pip install stable_baselines3[extra]\n", "# !pip install yfinance\n", "# !pip install talib-binary\n", "# !pip install huggingface_sb3\n" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "id": "LNXxxKojNTiL" }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "\n" ] } ], "source": [ "import gym\n", "from gym import spaces\n", "from gym.utils import seeding\n", "\n", "import talib as ta\n", "from tqdm.notebook import tqdm\n", "\n", "import yfinance as yf\n", "import pandas as pd\n", "import numpy as np\n", "from matplotlib import pyplot as plt\n" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "id": "dmAuEhZZNTiL" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "3024\n", "1875\n" ] } ], "source": [ "# Get data\n", "eth_usd = yf.Ticker(\"ETH-USD\")\n", "eth = eth_usd.history(period=\"max\")\n", "\n", "btc_usd = yf.Ticker(\"BTC-USD\")\n", "btc = btc_usd.history(period=\"max\")\n", "print(len(btc))\n", "print(len(eth))\n", "\n", "btc_train = eth[-3015:-200]\n", "# btc_test = eth[-200:]\n", "eth_train = eth[-1864:-200]\n", "eth_test = eth[-200:]\n", "# len(eth_train)" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "def initialize_q_table(state_space, action_space):\n", " Qtable = np.zeros((state_space, action_space))\n", " return Qtable" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "# Policy\n", "\n", "def greedy_policy(Qtable, state):\n", " # Exploitation: take the action with the highest state, action value\n", " # if we dont have a state with values return DO_NOTHING \n", " if abs(np.max(Qtable[state])) > 0:\n", " action = np.argmax(Qtable[state])\n", " else:\n", " action = 2\n", " # action = np.argmax(Qtable[state])\n", " return action\n", "\n", "\n", "def epsilon_greedy_policy(Qtable, state, epsilon, env):\n", " # Randomly generate a number between 0 and 1\n", " random_num = np.random.uniform(size=1)\n", " # if random_num > greater than epsilon --> exploitation\n", " if random_num > epsilon:\n", " # Take the action with the highest value given a state\n", " # np.argmax can be useful here\n", " action = greedy_policy(Qtable, state)\n", " # else --> exploration\n", " else:\n", " # action = np.random.random_integers(4,size=1)[0]\n", " action = env.action_space.sample()\n", " \n", " return action" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "id": "wlC-EdLENTiN" }, "outputs": [], "source": [ "def train(n_training_episodes, min_epsilon, max_epsilon, decay_rate, env, max_steps, Qtable, learning_rate, gamma):\n", " state_history = []\n", " \n", " for episode in range(n_training_episodes):\n", " # Reduce epsilon (because we need less and less exploration)\n", " epsilon = min_epsilon + (max_epsilon - min_epsilon)*np.exp(-decay_rate*episode)\n", " # Reset the environment\n", " state = env.reset()\n", " step = 0\n", " done = False\n", "\n", " # repeat\n", " for step in range(max_steps):\n", " # Choose the action At using epsilon greedy policy\n", " action = epsilon_greedy_policy(Qtable, state, epsilon, env)\n", "\n", " # Take action At and observe Rt+1 and St+1\n", " # Take the action (a) and observe the outcome state(s') and reward (r)\n", " new_state, reward, done, info = env.step(action)\n", "\n", " # Update Q(s,a):= Q(s,a) + lr [R(s,a) + gamma * max Q(s',a') - Q(s,a)]\n", " Qtable[state][action] = Qtable[state][action] + learning_rate * (reward + gamma * ( np.max(Qtable[new_state]) ) - Qtable[state][action] )\n", "\n", " # If done, finish the episode\n", " if done:\n", " break\n", " \n", " # Our next state is the new state\n", " state = new_state\n", "\n", " state_history.append(state) \n", "\n", " return Qtable, state_history" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "from enum import Enum\n", "class Actions(Enum):\n", " Sell = 0\n", " Buy = 1\n", " Do_nothing = 2\n", "\n", "class CustTradingEnv(gym.Env):\n", "\n", " def __init__(self, df, max_steps=0, random_start=True):\n", " self.seed()\n", " self.df = df\n", " self.prices, self.signal_features = self._process_data()\n", "\n", " # spaces\n", " self.action_space = spaces.Discrete(3)\n", " self.observation_space = spaces.Box(low=0, high=1999, shape=(1,) , dtype=np.float64)\n", "\n", " # episode\n", " self._start_tick = 0\n", " self._end_tick = 0\n", " self._done = None\n", " self._current_tick = None\n", " self._last_trade_tick = None\n", " self._position = None\n", " self._position_history = None\n", " self._total_reward = None\n", " self._total_profit = None\n", " self._first_rendering = None\n", " self.history = None\n", " self._max_steps = max_steps\n", " self._start_episode_tick = None\n", " self._trade_history = None\n", " self._random_start = random_start\n", "\n", " def reset(self):\n", " self._done = False\n", " if self._random_start:\n", " self._start_episode_tick = np.random.randint(1,high=len(self.df)- self._max_steps )\n", " self._end_tick = self._start_episode_tick + self._max_steps\n", " else:\n", " self._start_episode_tick = 1\n", " self._end_tick = len(self.df)-1\n", " # self._start_episode_tick = np.random.randint(1,len(self.df)- self._max_steps )\n", " # self._end_tick = self._start_episode_tick + self._max_steps\n", " self._current_tick = self._start_episode_tick\n", " self._last_trade_tick = self._current_tick - 1\n", " self._position = 0\n", " self._position_history = []\n", " # self._position_history = (self.window_size * [None]) + [self._position]\n", " self._total_reward = 0.\n", " self._total_profit = 0.\n", " self._trade_history = []\n", " self.history = {}\n", " return self._get_observation()\n", "\n", "\n", " def step(self, action):\n", " self._done = False\n", " self._current_tick += 1\n", "\n", " if self._current_tick == self._end_tick:\n", " self._done = True\n", "\n", " step_reward = self._calculate_reward(action)\n", " self._total_reward += step_reward\n", "\n", " observation = self._get_observation()\n", " info = dict(\n", " total_reward = self._total_reward,\n", " total_profit = self._total_profit,\n", " position = self._position,\n", " action = action\n", " )\n", " self._update_history(info)\n", "\n", " return observation, step_reward, self._done, info\n", "\n", " def seed(self, seed=None):\n", " self.np_random, seed = seeding.np_random(seed)\n", " return [seed]\n", " \n", " def _get_observation(self):\n", " return self.signal_features[self._current_tick]\n", "\n", " def _update_history(self, info):\n", " if not self.history:\n", " self.history = {key: [] for key in info.keys()}\n", "\n", " for key, value in info.items():\n", " self.history[key].append(value)\n", "\n", "\n", " def render(self, mode='human'):\n", " window_ticks = np.arange(len(self._position_history))\n", " prices = self.prices[self._start_episode_tick:self._end_tick+1]\n", " plt.plot(prices)\n", "\n", " open_buy = []\n", " close_buy = []\n", " open_sell = []\n", " close_sell = []\n", " do_nothing = []\n", "\n", " for i, tick in enumerate(window_ticks):\n", " if self._position_history[i] == 1:\n", " open_buy.append(tick)\n", " elif self._position_history[i] == 2 :\n", " close_buy.append(tick)\n", " elif self._position_history[i] == 3 :\n", " open_sell.append(tick)\n", " elif self._position_history[i] == 4 :\n", " close_sell.append(tick)\n", " elif self._position_history[i] == 0 :\n", " do_nothing.append(tick)\n", "\n", " plt.plot(open_buy, prices[open_buy], 'go', marker=\"^\")\n", " plt.plot(close_buy, prices[close_buy], 'go', marker=\"v\")\n", " plt.plot(open_sell, prices[open_sell], 'ro', marker=\"v\")\n", " plt.plot(close_sell, prices[close_sell], 'ro', marker=\"^\")\n", " \n", " plt.plot(do_nothing, prices[do_nothing], 'yo')\n", "\n", " plt.suptitle(\n", " \"Total Reward: %.6f\" % self._total_reward + ' ~ ' +\n", " \"Total Profit: %.6f\" % self._total_profit\n", " )\n", "\n", " def _calculate_reward(self, action):\n", " step_reward = 0\n", "\n", " current_price = self.prices[self._current_tick]\n", " last_price = self.prices[self._current_tick - 1]\n", " price_diff = current_price - last_price\n", "\n", " penalty = -1 * last_price * 0.01\n", " # OPEN BUY - 1\n", " if action == Actions.Buy.value and self._position == 0:\n", " self._position = 1\n", " step_reward += price_diff\n", " self._last_trade_tick = self._current_tick - 1\n", " self._position_history.append(1)\n", "\n", " elif action == Actions.Buy.value and self._position > 0:\n", " step_reward += penalty\n", " self._position_history.append(-1)\n", " # CLOSE SELL - 4\n", " elif action == Actions.Buy.value and self._position < 0:\n", " self._position = 0\n", " step_reward += -1 * (self.prices[self._current_tick -1] - self.prices[self._last_trade_tick]) \n", " self._total_profit += step_reward\n", " self._position_history.append(4)\n", " self._trade_history.append(step_reward)\n", "\n", " # OPEN SELL - 3\n", " elif action == Actions.Sell.value and self._position == 0:\n", " self._position = -1\n", " step_reward += -1 * price_diff\n", " self._last_trade_tick = self._current_tick - 1\n", " self._position_history.append(3)\n", " # CLOSE BUY - 2\n", " elif action == Actions.Sell.value and self._position > 0:\n", " self._position = 0\n", " step_reward += self.prices[self._current_tick -1] - self.prices[self._last_trade_tick] \n", " self._total_profit += step_reward\n", " self._position_history.append(2)\n", " self._trade_history.append(step_reward)\n", " elif action == Actions.Sell.value and self._position < 0:\n", " step_reward += penalty\n", " self._position_history.append(-1)\n", "\n", " # DO NOTHING - 0\n", " elif action == Actions.Do_nothing.value and self._position > 0:\n", " step_reward += price_diff\n", " self._position_history.append(0)\n", " elif action == Actions.Do_nothing.value and self._position < 0:\n", " step_reward += -1 * price_diff\n", " self._position_history.append(0)\n", " elif action == Actions.Do_nothing.value and self._position == 0:\n", " step_reward += -1 * abs(price_diff)\n", " self._position_history.append(0)\n", "\n", " return step_reward\n", "\n", " def _do_bin(self,df):\n", " df = pd.cut(df,bins=[0,10,20,30,40,50,60,70,80,90,100],labels=False, include_lowest=True)\n", " return df\n", " # Our state will be encode with 4 features MFI and Stochastic(only D line), ADX and DI+DI-\n", " # the values of each feature will be binned in 10 bins, ex:\n", " # MFI goes from 0-100, if we get 25 will put on the second bin \n", " # DI+DI- if DI+ is over DI- set (1 otherwise 0) \n", " # \n", " # that will give a state space of 10(MFI) * 10(STOCH) * 10(ADX) * 2(DI) = 2000 states\n", " # encoded as bins of DI MFI STOCH ADX = 1 45.2 25.4 90.1 , binned = 1 4 2 9 state = 1429 \n", " def _process_data(self):\n", " timeperiod = 14\n", " self.df = self.df.copy()\n", " \n", " self.df['mfi_r'] = ta.MFI(self.df['High'], self.df['Low'], self.df['Close'],self.df['Volume'], timeperiod=timeperiod)\n", " _, self.df['stock_d_r'] = ta.STOCH(self.df['High'], self.df['Low'], self.df['Close'], fastk_period=5, slowk_period=3, slowk_matype=0, slowd_period=3, slowd_matype=0)\n", " self.df['adx_r'] = ta.ADX(self.df['High'], self.df['Low'], self.df['Close'], timeperiod=timeperiod)\n", " self.df['p_di'] = ta.PLUS_DI(self.df['High'], self.df['Low'], self.df['Close'], timeperiod=timeperiod)\n", " self.df['m_di'] = ta.MINUS_DI(self.df['High'], self.df['Low'], self.df['Close'], timeperiod=timeperiod)\n", " self.df['di'] = np.where( self.df['p_di'] > self.df['m_di'], 1, 0)\n", "\n", " self.df = self.df.dropna()\n", " self.df['mfi'] = self._do_bin(self.df['mfi_r'])\n", " self.df['stock_d'] = self._do_bin(self.df['stock_d_r'])\n", " self.df['adx'] = self._do_bin(self.df['adx_r'])\n", " self.df['state'] = self.df['di']*1000+ self.df['mfi']*100 + self.df['stock_d']*10 + self.df['adx']\n", "\n", " prices = self.df.loc[:, 'Close'].to_numpy()\n", " # print(self.df.head(30))\n", "\n", " signal_features = self.df.loc[:, 'state'].to_numpy()\n", "\n", " return prices, signal_features" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "# Training parameters\n", "n_training_episodes = 20000 # Total training episodes\n", "learning_rate = 0.2 # Learning rate\n", "\n", "# Environment parameters\n", "max_steps = 20 # Max steps per episode\n", "gamma = 0.95 # Discounting rate\n", "\n", "# Exploration parameters\n", "max_epsilon = 1.0 # Exploration probability at start\n", "# max_epsilon = 1.0 # Exploration probability at start\n", "min_epsilon = 0.05 # Minimum exploration probability \n", "# min_epsilon = 0.05 # Minimum exploration probability \n", "decay_rate = 0.0005 # Exponential decay rate for exploration prob" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "REhmfLkYNTiN", "outputId": "cf676f6d-83df-43f5-89fe-3258e0041d9d" }, "outputs": [], "source": [ "# create env\n", "env = CustTradingEnv(df=eth_train, max_steps=max_steps)" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [], "source": [ "# create q-table\n", "\n", "action_space = env.action_space.n # buy sell do_nothing\n", "state_space = 2000\n", "\n", "Qtable_trading = initialize_q_table(state_space, action_space)" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "981" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# train with ETH\n", "Qtable_trading, state_history = train(n_training_episodes, min_epsilon, max_epsilon, \n", " decay_rate, env, max_steps, Qtable_trading, learning_rate, gamma )\n", "len(np.where( Qtable_trading > 0 )[0])\n", "\n", "# #train with BTC\n", "# env = CustTradingEnv(df=btc_train, max_steps=max_steps)\n", "# Qtable_trading, state_history = train(n_training_episodes, min_epsilon, max_epsilon, \n", "# decay_rate, env, max_steps, Qtable_trading, learning_rate, gamma )\n", "# len(np.where( Qtable_trading > 0 )[0])" ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 417 }, "id": "FIQ0OqtsO3jo", "outputId": "f98374ad-c7de-4dc4-80b1-25f018ad96eb" }, "outputs": [ { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "plt.figure(figsize=(15,6))\n", "plt.cla()\n", "env.render()\n", "plt.show()" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[-168.9210205078125, 187.22998046875, 218.34100341796875]" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "env._trade_history" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "351" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "len(np.unique(state_history, return_counts=True)[1])\n", "# count = 0\n", "# for i in range(len(state_history)):\n", "# if state_history[i] == 1987:\n", "# count +=1\n", "# count" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [], "source": [ "def evaluate_agent(env, max_steps, n_eval_episodes, Q, random=False):\n", " \"\"\"\n", " Evaluate the agent for ``n_eval_episodes`` episodes and returns average reward and std of reward.\n", " :param env: The evaluation environment\n", " :param n_eval_episodes: Number of episode to evaluate the agent\n", " :param Q: The Q-table\n", " :param seed: The evaluation seed array (for taxi-v3)\n", " \"\"\"\n", " episode_rewards = []\n", " episode_profits = []\n", " for episode in tqdm(range(n_eval_episodes), disable=random):\n", " state = env.reset()\n", " step = 0\n", " done = False\n", " total_rewards_ep = 0\n", " total_profit_ep = 0\n", " \n", " for step in range(max_steps):\n", " # Take the action (index) that have the maximum expected future reward given that state\n", " if random:\n", " action = env.action_space.sample()\n", " else:\n", " action = greedy_policy(Q, state)\n", "\n", " new_state, reward, done, info = env.step(action)\n", " total_rewards_ep += reward\n", " \n", " if done:\n", " break\n", " state = new_state\n", "\n", " episode_rewards.append(total_rewards_ep)\n", " episode_profits.append(env.history['total_profit'][-1])\n", " # print(env.history)\n", " # env.render()\n", " # assert 0\n", "\n", " mean_reward = np.mean(episode_rewards)\n", " std_reward = np.std(episode_rewards)\n", " mean_profit = np.mean(episode_profits)\n", " std_profit = np.std(episode_profits)\n", "\n", " return mean_reward, std_reward, mean_profit, std_profit" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "629507e6932b49d381644ae851b9f08e", "version_major": 2, "version_minor": 0 }, "text/plain": [ " 0%| | 0/1000 [00:00" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "plt.figure(figsize=(15,6))\n", "plt.cla()\n", "env_test.render()" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "65be242101434cab9057cda9dd230391", "version_major": 2, "version_minor": 0 }, "text/plain": [ " 0%| | 0/1 [00:00 0:\n", " count+=1\n", " # else:\n", " # print(i)\n", " # assert 0\n", " \n", " print(len(env.signal_features), count, count / len(env.signal_features))\n", "\n", "count_equal(env_test, Qtable_trading)" ] } ], "metadata": { "colab": { "provenance": [] }, "kernelspec": { "display_name": "Python 3.8.13 ('rl2')", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.13" }, "orig_nbformat": 4, "vscode": { "interpreter": { "hash": "cd60ab8388a66026f336166410d6a8a46ddf65ece2e85ad2d46c8b98d87580d1" } }, "widgets": { "application/vnd.jupyter.widget-state+json": { "01a2dbcb714e40148b41c761fcf43147": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": { "_model_module": "@jupyter-widgets/base", "_model_module_version": "1.2.0", "_model_name": "LayoutModel", "_view_count": null, "_view_module": "@jupyter-widgets/base", "_view_module_version": "1.2.0", "_view_name": "LayoutView", "align_content": null, "align_items": null, "align_self": null, "border": null, "bottom": null, "display": null, "flex": null, "flex_flow": null, "grid_area": null, "grid_auto_columns": null, "grid_auto_flow": null, "grid_auto_rows": null, "grid_column": null, "grid_gap": null, "grid_row": null, "grid_template_areas": null, "grid_template_columns": null, "grid_template_rows": null, "height": null, "justify_content": null, "justify_items": null, "left": null, "margin": null, "max_height": null, "max_width": null, "min_height": null, "min_width": null, "object_fit": null, "object_position": null, "order": null, "overflow": null, "overflow_x": null, "overflow_y": null, "padding": null, "right": null, "top": null, "visibility": null, "width": null } }, "20b0f38ec3234ff28a62a286cd57b933": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "PasswordModel", "state": { "_dom_classes": [], "_model_module": "@jupyter-widgets/controls", "_model_module_version": "1.5.0", "_model_name": "PasswordModel", "_view_count": null, "_view_module": "@jupyter-widgets/controls", "_view_module_version": "1.5.0", "_view_name": "PasswordView", "continuous_update": true, "description": "Token:", "description_tooltip": null, "disabled": false, "layout": "IPY_MODEL_01a2dbcb714e40148b41c761fcf43147", "placeholder": "​", "style": "IPY_MODEL_90c874e91b304ee1a7ef147767ac00ce", "value": "" } }, "270cbb5d6e9c4b1e9e2f39c8b3b0c15f": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "VBoxModel", "state": { "_dom_classes": [], "_model_module": "@jupyter-widgets/controls", "_model_module_version": "1.5.0", "_model_name": "VBoxModel", "_view_count": null, "_view_module": "@jupyter-widgets/controls", "_view_module_version": "1.5.0", "_view_name": "VBoxView", "box_style": "", "children": [ "IPY_MODEL_a02224a43d8d4af3bd31d326540d25da", "IPY_MODEL_20b0f38ec3234ff28a62a286cd57b933", "IPY_MODEL_f6c845330d6743c0b35c2c7ad834de77", "IPY_MODEL_f1675c09d16a4251b403f9c56255f168", "IPY_MODEL_c1a82965ae26479a98e4fdbde1e64ec2" ], "layout": "IPY_MODEL_3fa248114ac24656ba74923936a94d2d" } }, "2dc5fa9aa3334dfcbdee9c238f2ef60b": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "DescriptionStyleModel", "state": { "_model_module": "@jupyter-widgets/controls", "_model_module_version": "1.5.0", "_model_name": "DescriptionStyleModel", "_view_count": null, "_view_module": "@jupyter-widgets/base", "_view_module_version": "1.2.0", "_view_name": "StyleView", "description_width": "" } }, "3e753b0212644990b558c68853ff2041": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": { "_model_module": "@jupyter-widgets/base", "_model_module_version": "1.2.0", "_model_name": "LayoutModel", "_view_count": null, "_view_module": "@jupyter-widgets/base", "_view_module_version": "1.2.0", "_view_name": "LayoutView", "align_content": null, "align_items": null, "align_self": null, "border": null, "bottom": null, "display": null, "flex": null, "flex_flow": null, "grid_area": null, "grid_auto_columns": null, "grid_auto_flow": null, "grid_auto_rows": null, "grid_column": null, "grid_gap": null, "grid_row": null, "grid_template_areas": null, "grid_template_columns": null, "grid_template_rows": null, "height": null, "justify_content": null, "justify_items": null, "left": null, "margin": null, "max_height": null, "max_width": null, "min_height": null, "min_width": null, "object_fit": null, "object_position": null, "order": null, "overflow": null, "overflow_x": null, "overflow_y": null, "padding": null, "right": null, "top": null, "visibility": null, "width": null } }, "3fa248114ac24656ba74923936a94d2d": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": { "_model_module": "@jupyter-widgets/base", "_model_module_version": "1.2.0", "_model_name": "LayoutModel", "_view_count": null, "_view_module": "@jupyter-widgets/base", "_view_module_version": "1.2.0", "_view_name": "LayoutView", "align_content": null, "align_items": "center", "align_self": null, "border": null, "bottom": null, "display": "flex", "flex": null, "flex_flow": "column", "grid_area": null, "grid_auto_columns": null, "grid_auto_flow": null, "grid_auto_rows": null, "grid_column": null, "grid_gap": null, "grid_row": null, "grid_template_areas": null, "grid_template_columns": null, "grid_template_rows": null, "height": null, "justify_content": null, "justify_items": null, "left": null, "margin": null, "max_height": null, "max_width": null, "min_height": null, "min_width": null, "object_fit": null, "object_position": null, "order": null, "overflow": null, "overflow_x": null, "overflow_y": null, "padding": null, "right": null, "top": null, "visibility": null, "width": "50%" } }, "42d140b838b844819bc127afc1b7bc84": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "DescriptionStyleModel", "state": { "_model_module": "@jupyter-widgets/controls", "_model_module_version": "1.5.0", "_model_name": "DescriptionStyleModel", "_view_count": null, "_view_module": "@jupyter-widgets/base", "_view_module_version": "1.2.0", "_view_name": "StyleView", "description_width": "" } }, "90c874e91b304ee1a7ef147767ac00ce": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "DescriptionStyleModel", "state": { "_model_module": "@jupyter-widgets/controls", "_model_module_version": "1.5.0", "_model_name": "DescriptionStyleModel", "_view_count": null, "_view_module": "@jupyter-widgets/base", "_view_module_version": "1.2.0", "_view_name": "StyleView", "description_width": "" } }, "9d847f9a7d47458d8cd57d9b599e47c6": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": { "_model_module": "@jupyter-widgets/base", "_model_module_version": "1.2.0", "_model_name": "LayoutModel", "_view_count": null, "_view_module": "@jupyter-widgets/base", "_view_module_version": "1.2.0", "_view_name": "LayoutView", "align_content": null, "align_items": null, "align_self": null, "border": null, "bottom": null, "display": null, "flex": null, "flex_flow": null, "grid_area": null, "grid_auto_columns": null, "grid_auto_flow": null, "grid_auto_rows": null, "grid_column": null, "grid_gap": null, "grid_row": null, "grid_template_areas": null, "grid_template_columns": null, "grid_template_rows": null, "height": null, "justify_content": null, "justify_items": null, "left": null, "margin": null, "max_height": null, "max_width": null, "min_height": null, "min_width": null, "object_fit": null, "object_position": null, "order": null, "overflow": null, "overflow_x": null, "overflow_y": null, "padding": null, "right": null, "top": null, "visibility": null, "width": null } }, "a02224a43d8d4af3bd31d326540d25da": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "HTMLModel", "state": { "_dom_classes": [], "_model_module": "@jupyter-widgets/controls", "_model_module_version": "1.5.0", "_model_name": "HTMLModel", "_view_count": null, "_view_module": "@jupyter-widgets/controls", "_view_module_version": "1.5.0", "_view_name": "HTMLView", "description": "", "description_tooltip": null, "layout": "IPY_MODEL_caef095934ec47bbb8b64eab22049284", "placeholder": "​", "style": "IPY_MODEL_2dc5fa9aa3334dfcbdee9c238f2ef60b", "value": "

Copy a token from your Hugging Face\ntokens page and paste it below.
Immediately click login after copying\nyour token or it might be stored in plain text in this notebook file.
" } }, "a2cfb91cf66447d7899292854bd64a07": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": { "_model_module": "@jupyter-widgets/base", "_model_module_version": "1.2.0", "_model_name": "LayoutModel", "_view_count": null, "_view_module": "@jupyter-widgets/base", "_view_module_version": "1.2.0", "_view_name": "LayoutView", "align_content": null, "align_items": null, "align_self": null, "border": null, "bottom": null, "display": null, "flex": null, "flex_flow": null, "grid_area": null, "grid_auto_columns": null, "grid_auto_flow": null, "grid_auto_rows": null, "grid_column": null, "grid_gap": null, "grid_row": null, "grid_template_areas": null, "grid_template_columns": null, "grid_template_rows": null, "height": null, "justify_content": null, "justify_items": null, "left": null, "margin": null, "max_height": null, "max_width": null, "min_height": null, "min_width": null, "object_fit": null, "object_position": null, "order": null, "overflow": null, "overflow_x": null, "overflow_y": null, "padding": null, "right": null, "top": null, "visibility": null, "width": null } }, "c1a82965ae26479a98e4fdbde1e64ec2": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "HTMLModel", "state": { "_dom_classes": [], "_model_module": "@jupyter-widgets/controls", "_model_module_version": "1.5.0", "_model_name": "HTMLModel", "_view_count": null, "_view_module": "@jupyter-widgets/controls", "_view_module_version": "1.5.0", "_view_name": "HTMLView", "description": "", "description_tooltip": null, "layout": "IPY_MODEL_9d847f9a7d47458d8cd57d9b599e47c6", "placeholder": "​", "style": "IPY_MODEL_42d140b838b844819bc127afc1b7bc84", "value": "\nPro Tip: If you don't already have one, you can create a dedicated\n'notebooks' token with 'write' access, that you can then easily reuse for all\nnotebooks. " } }, "caef095934ec47bbb8b64eab22049284": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": { "_model_module": "@jupyter-widgets/base", "_model_module_version": "1.2.0", "_model_name": "LayoutModel", "_view_count": null, "_view_module": "@jupyter-widgets/base", "_view_module_version": "1.2.0", "_view_name": "LayoutView", "align_content": null, "align_items": null, "align_self": null, "border": null, "bottom": null, "display": null, "flex": null, "flex_flow": null, "grid_area": null, "grid_auto_columns": null, "grid_auto_flow": null, "grid_auto_rows": null, "grid_column": null, "grid_gap": null, "grid_row": null, "grid_template_areas": null, "grid_template_columns": null, "grid_template_rows": null, "height": null, "justify_content": null, "justify_items": null, "left": null, "margin": null, "max_height": null, "max_width": null, "min_height": null, "min_width": null, "object_fit": null, "object_position": null, "order": null, "overflow": null, "overflow_x": null, "overflow_y": null, "padding": null, "right": null, "top": null, "visibility": null, "width": null } }, "eaba3f1de4444aabadfea2a3dadb1d80": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "DescriptionStyleModel", "state": { "_model_module": "@jupyter-widgets/controls", "_model_module_version": "1.5.0", "_model_name": "DescriptionStyleModel", "_view_count": null, "_view_module": "@jupyter-widgets/base", "_view_module_version": "1.2.0", "_view_name": "StyleView", "description_width": "" } }, "ee4a21bedc504171ad09d205d634b528": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "ButtonStyleModel", "state": { "_model_module": "@jupyter-widgets/controls", "_model_module_version": "1.5.0", "_model_name": "ButtonStyleModel", "_view_count": null, "_view_module": "@jupyter-widgets/base", "_view_module_version": "1.2.0", "_view_name": "StyleView", "button_color": null, "font_weight": "" } }, "f1675c09d16a4251b403f9c56255f168": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "ButtonModel", "state": { "_dom_classes": [], "_model_module": "@jupyter-widgets/controls", "_model_module_version": "1.5.0", "_model_name": "ButtonModel", "_view_count": null, "_view_module": "@jupyter-widgets/controls", "_view_module_version": "1.5.0", "_view_name": "ButtonView", "button_style": "", "description": "Login", "disabled": false, "icon": "", "layout": "IPY_MODEL_a2cfb91cf66447d7899292854bd64a07", "style": "IPY_MODEL_ee4a21bedc504171ad09d205d634b528", "tooltip": "" } }, "f6c845330d6743c0b35c2c7ad834de77": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "CheckboxModel", "state": { "_dom_classes": [], "_model_module": "@jupyter-widgets/controls", "_model_module_version": "1.5.0", "_model_name": "CheckboxModel", "_view_count": null, "_view_module": "@jupyter-widgets/controls", "_view_module_version": "1.5.0", "_view_name": "CheckboxView", "description": "Add token as git credential?", "description_tooltip": null, "disabled": false, "indent": true, "layout": "IPY_MODEL_3e753b0212644990b558c68853ff2041", "style": "IPY_MODEL_eaba3f1de4444aabadfea2a3dadb1d80", "value": true } } } } }, "nbformat": 4, "nbformat_minor": 0 }