<jupyter_start><jupyter_text>When predicting a large number of classes it often becomes inefficient to train a generalized linear model for each distinct class (i.e. the parameters for each softmax node at the end of a neural network). On proposed solution has been to use offline clustering of output label representations to create binary codes for each label and then use log(G) distinct sigmoid outputs at the end of a neural network (see "A Scalable Hierarchical Distributed Language Model" by Hinton and Mnih). Why not instead learn an optimal encoding of the output labels interleaved with training the predictive model? Here we're experimenting with assigning initial random codes, training a multi-output linear regression, and then finding better output codes by averaging the predicted output codes of samples associated with each class.<jupyter_code>import sklearn
data = sklearn.datasets.fetch_20newsgroups_vectorized()
data
X = data['data']; Y = data['target']
model = sklearn.linear_model.Ridge()
from sklearn.feature_extraction.text import TfidfTransformer
tfidf = TfidfTransformer(use_idf=False).fit(X)
X_tfidf = tfidf.transform(X)
n_samples = len(Y)
n_labels = len(set(Y))
n_bits = int(np.ceil(np.log2(n_labels)))
# generate random binary codes for each output labels
output_codes = {}
 
for output_label in set(Y):
    candidate_code = tuple((np.random.randn(n_bits) > 0).astype(float))
    while candidate_code in output_codes.values():
        candidate_code = tuple((np.random.randn(n_bits) > 0).astype(float))
    output_codes[output_label] = candidate_code
output_codes
encoded_Y = np.array([output_codes[yi] for yi in Y])
encoded_Y
model.fit(X_tfidf, encoded_Y)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.07634032634032634, 'fraction_numerical': 0.002913752913752914, 'mean_word_length': 5.813492063492063, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '1', 'dir': 'jupyter-structured-clean-dedup', 'id': '583790', 'license': 'Apache-2.0', 'n_tokens_mistral': 508, 'n_tokens_neox': 488, 'n_words': 187, 'path': 'Large Number of Output Classes.ipynb', 'repo_name': 'iskandr/seqlearn', 'size': '1716'}