{ "cells": [ { "cell_type": "markdown", "metadata": { "id": "nwaAZRu1NTiI" }, "source": [ "# Q-learning \n", "\n", "#### This version implements q-learning with a finner binned state v1 uses 0-10 to bin this version uses 0-5\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "DDf1gLC2NTiK" }, "outputs": [], "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": 14, "metadata": { "id": "LNXxxKojNTiL" }, "outputs": [], "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": 15, "metadata": { "id": "dmAuEhZZNTiL" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "3015\n", "1866\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": 16, "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": 17, "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": 18, "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": 19, "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):\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", "\n", " def reset(self):\n", " self._done = False\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):\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,5,10,15,20,25,30,35,40,45,50,55,60,65,70,75,80,85,90,95,100],labels=False, include_lowest=True)\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", "\n", " def _process_data(self):\n", " \"\"\"\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 21 bins, ex:\n", " MFI goes from 0-100, if we get 25 will put on the 4 bin \n", " DI+DI- if DI+ is over DI- set (1 otherwise 0) \n", "\n", " \"\"\"\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']*1000000+ self.df['mfi']*10000 + self.df['stock_d']*100 + 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": 36, "metadata": {}, "outputs": [], "source": [ "# Training parameters\n", "n_training_episodes = 50000 # 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": 37, "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": 44, "metadata": {}, "outputs": [], "source": [ "# create q-table\n", "\n", "action_space = env.action_space.n # buy sell do_nothing\n", "state_space = 2_000_000\n", "\n", "Qtable_trading = initialize_q_table(state_space, action_space)" ] }, { "cell_type": "code", "execution_count": 45, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3099" ] }, "execution_count": 45, "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": 46, "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": 41, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[19.9169921875,\n", " 26.519012451171875,\n", " 4.449005126953125,\n", " -9.738006591796875,\n", " -5.11199951171875]" ] }, "execution_count": 41, "metadata": {}, "output_type": "execute_result" } ], "source": [ "env._trade_history" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1030" ] }, "execution_count": 28, "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": 29, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1031" ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Qtable_trading[1987]\n", "len(np.unique(env.signal_features))" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [], "source": [ "def evaluate_agent(env, max_steps, n_eval_episodes, Q):\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)):\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", " action = greedy_policy(Q, state)\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": 57, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "d75c69746f3e486ab8ccd39d180bf059", "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": 50, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "173 78 0.4508670520231214\n" ] } ], "source": [ "def count_equal(env, Qtable):\n", " count=0\n", " for i in env.signal_features:\n", " if abs(np.max(Qtable[i])) > 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)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "np.unique(env_test.signal_features, return_counts=True)" ] } ], "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 }