Max Activation: {Math.max(...sampleGroup.samples[0].featureActs).toFixed(3)}
- {sampleGroup.samples.slice((page - 1) * 5, page * 5).map((sample, i) => (
+ {sampleGroup.samples.slice((page - 1) * 10, page * 10).map((sample, i) => (
))}
@@ -69,18 +70,68 @@ export const FeatureActivationSample = ({ sample, sampleName, maxFeatureAct }: F
[0]
);
+ const tokensList = tokens.map((t) => t.featureAct);
+ const startTrigger = Math.max(tokensList.indexOf(Math.max(...tokensList)) - 100, 0);
+ const endTrigger = Math.min(tokensList.indexOf(Math.max(...tokensList)) + 10, sample.context.length);
+ const tokensTrigger = sample.context.slice(startTrigger, endTrigger).map((token, i) => ({
+ token,
+ featureAct: sample.featureActs[startTrigger + i],
+ }));
+
+ const [tokenGroupsTrigger, __] = tokensTrigger.reduce<[Token[][], Token[]]>(
+ ([groups, currentGroup], token) => {
+ const newGroup = [...currentGroup, token];
+ try {
+ decoder.decode(mergeUint8Arrays(newGroup.map((t) => t.token)));
+ return [[...groups, newGroup], []];
+ } catch {
+ return [groups, newGroup];
+ }
+ },
+ [[], []]
+ );
+
+ const tokenGroupPositionsTrigger = tokenGroupsTrigger.reduce
(
+ (acc, tokenGroup) => {
+ const tokenCount = tokenGroup.length;
+ return [...acc, acc[acc.length - 1] + tokenCount];
+ },
+ [0]
+ );
+
return (
- {sampleName &&
{sampleName}: }
- {tokenGroups.map((tokens, i) => (
-
- ))}
+
+
+
+
+ {sampleName && {sampleName}: }
+ {startTrigger != 0 && ...}
+ {tokenGroupsTrigger.map((tokens, i) => (
+
+ ))}
+ {endTrigger != 0 && ...}
+
+
+
+ {tokenGroups.map((tokens, i) => (
+
+ ))}
+
+
+
);
};
diff --git a/ui/src/components/ui/accordion.tsx b/ui/src/components/ui/accordion.tsx
index bb60ae5..3068d67 100644
--- a/ui/src/components/ui/accordion.tsx
+++ b/ui/src/components/ui/accordion.tsx
@@ -22,7 +22,7 @@ const AccordionTrigger = React.forwardRef<
svg]:rotate-180",
+ "flex flex-1 items-center justify-between py-4 font-medium transition-all [&[data-state=open]>svg]:rotate-180",
className
)}
{...props}
diff --git a/ui/src/globals.css b/ui/src/globals.css
index 9e24275..55ba9eb 100644
--- a/ui/src/globals.css
+++ b/ui/src/globals.css
@@ -74,3 +74,7 @@
@apply bg-background text-foreground;
}
}
+
+html {
+ scroll-behavior: smooth;
+}
diff --git a/ui/src/routes/features/page.tsx b/ui/src/routes/features/page.tsx
index f55925f..8ea03ee 100644
--- a/ui/src/routes/features/page.tsx
+++ b/ui/src/routes/features/page.tsx
@@ -1,5 +1,6 @@
import { AppNavbar } from "@/components/app/navbar";
import { FeatureCard } from "@/components/feature/feature-card";
+import { SectionNavigator } from "@/components/app/section-navigator";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
@@ -87,8 +88,23 @@ export const FeaturesPage = () => {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [dictionariesState.value]);
+ const sections = [
+ {
+ title: "Histogram",
+ id: "Histogram",
+ },
+ {
+ title: "Logits",
+ id: "Logits",
+ },
+ {
+ title: "Top Activation",
+ id: "Activation",
+ },
+ ].filter((section) => (featureState.value && featureState.value.logits != null) || section.id !== "Logits");
+
return (
-
+
@@ -142,6 +158,7 @@ export const FeaturesPage = () => {
Show Random Feature
+
{featureState.loading && !loadingRandomFeature && (
Loading Feature
#{featureIndex}...
@@ -149,7 +166,12 @@ export const FeaturesPage = () => {
)}
{featureState.loading && loadingRandomFeature &&
Loading Random Living Feature...
}
{featureState.error &&
Error: {featureState.error.message}
}
- {!featureState.loading && featureState.value &&
}
+ {!featureState.loading && featureState.value && (
+
+
+
+
+ )}
);