refiners/search/search_index.json

1 line
501 KiB
JSON
Raw Normal View History

{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"A PyTorch microframework for foundation model adaptation","text":"<p> <p>The simplest way to train and run adapters on top of foundation models.</p> <p> </p> <p>At the era of foundation models, adaptation is quickly rising at the method of choice for bridging the last mile quality gap. We couldn't find a framework with first class citizen APIs for foundation model adaptation, so we created one. It's called Refiners, and we're building it on top of PyTorch, in the open, under the MIT License. Read our manifesto.</p> <p></p>"},{"location":"concepts/chain/","title":"Chain","text":"<p>When we say models are implemented in a declarative way in Refiners, what this means in practice is they are implemented as Chains. <code>Chain</code> is a Python class to implement trees of modules. It is a subclass of Refiners' <code>Module</code>, which is in turn a subclass of PyTorch's <code>Module</code>. All inner nodes of a Chain are subclasses of <code>Chain</code>, and leaf nodes are subclasses of Refiners' <code>Module</code>.</p>"},{"location":"concepts/chain/#a-first-example","title":"A first example","text":"<p>To give you an idea of how it looks, let us take a simple convolution network to classify MNIST as an example. First, let us define a few variables.</p> <pre><code>img_res = 28\nchannels = 128\nkernel_size = 3\nhidden_layer_in = (((img_res - kernel_size + 1) // 2) ** 2) * channels\nhidden_layer_out = 200\noutput_size = 10\n</code></pre> <p>Now, here is the model in PyTorch:</p> <pre><code>class BasicModel(nn.Module):\n def __init__(self):\n super().__init__()\n self.conv = nn.Conv2d(1, channels, kernel_size)\n self.linear_1 = nn.Linear(hidden_layer_in, hidden_layer_out)\n self.maxpool = nn.MaxPool2d(2)\n self.linear_2 = nn.Linear(hidden_layer_out, output_size)\n\n def forward(self, x):\n x = self.conv(x)\n x = nn.functional.relu(x)\n x = self.maxpool(x)\n x = x.flatten(start_dim=1)\n x = self.linear_1(x)\n x = nn.functional.relu(x)\n x = self.linear_2(x)\n return nn.functional.softmax(x, dim=0)\n</code></pre> <p>And here is how we could implement the same model in Refiners:</p> <pre><code>class BasicModel(fl.Chain):\n def __init__(self):\n super().__init__(\n fl.Conv2d(1, channels, kernel_size),\n fl.ReLU(),\n fl.MaxPool2d(2),\n fl.Flatten(start_dim=1),\n fl.Linear(hidden_layer_in, hidden_layer_out),\n fl.ReLU(),\n fl.Linear(hidden_layer_out, output_size),\n fl.Lambda(lambda x: torch.nn.functional.softmax(x, dim=0)),\n )\n</code></pre> <p>Note</p> <p>We often use the namespace <code>fl</code> which means <code>fluxion</code>, which is the name of the part of Refiners that implements basic layers.</p> <p>As of writing, Refiners does not include a <code>Softmax</code> layer by default, but as you can see you can easily call arbitrary code using <code>fl.Lambda</code>. Alternatively, if you just wanted to write <code>Softmax()</code>, you could implement it like this:</p> <pre><code>class Softmax(fl.Module):\n def forward(self, x: torch.Tensor) -&gt; torch.Tensor:\n return torch.nn.functional.softmax(x, dim=0)\n</code></pre> <p>Note</p> <p>Notice the type hints here. All of Refiners' codebase is typed, which makes it a pleasure to use if your downstream code is typed too.</p>"},{"location":"concepts/chain/#inspecting-and-manipulating","title":"Inspecting and manipulating","text":"<p>Let us instantiate the <code>BasicModel</code> we just defined and inspect its representation in a Python REPL:</p> <pre><code>&gt;&gt;&gt; m = BasicModel()\n&gt;&gt;&gt; m\n(CHAIN) BasicModel()\n \u251c\u2500\u2500 Conv2d(in_channels=1, out_channels=128, kernel_size=(3, 3), device=cpu, dtype=float32)\n \u251c\u2500\u2500 ReLU() #1\n \u251c\u2500\u2500 MaxPool2d(kernel_size=2, stride=2)\n \u251c\u2500\u2500 Flat