About Me

C:\Users\aaron> python
Python 3.8.0 (tags/v3.8.0:fa919fd, Oct 14 2019, 19:37:50) [MSC v.1916 64 bit (AMD64)] on win32 Type "help", "copyright", "credits" or "license" for more information.

>>> class Person():

def __init__(self):

"""
I’m Aaron Tian, a Junior at the Massachusetts Academy of Math and Science. I was apprehensive about leaving my hometown of Westborough at first, but after coming to MAMS I can confidently state that I have no regrets. I love what I do here, and I hope to share that passion with you through this portfolio—or ‘class,’ if you will.
"""


self.name = "Aaron Tian"

self.age = 16.

self.can_play_piano = False

scroll down to learn more about me!

me :)

Clarinet

def getFavoritePieces(self, num_tracks, genre='classical'):

self.playlist = pickle.load(open('Data/playlist'))

num_tracks = min(num_tracks, len(self.playlist))


if genre == 'classical':

return self.playlist[:num_tracks]

else:

return f'{self.name} does not have anything other than classical music in his playlist, but he reserves "Castle on the Hill - Ed Sheeran" as his favorite pop song in case anyone asks.'


>>> .getFavoritePieces(5)

['Ballade no. 1 - Chopin', 'Widmung - Schumann arr. Liszt', 'Danse Macabre - Saint Saens', 'Etude op. 10 no. 3 - Chopin', 'Carmen Fantaisie - Sarasate arr. Baldeyrou']

me looking confused

My Origin Story

I didn’t even know what a clarinet was until the moment I decided to play it. In the 4th grade, I was shown a demonstrative video of wind instruments as part of an effort to recruit students to the band. One line caught my attention: “the clarinet has the widest range of all woodwinds.” Something about being able to play more notes than everyone else appealed to me, and I’ve stuck with the clarinet ever since. I don’t think I was particularly good at it early on; I was also playing piano and viola then, and I lacked the time and dedication to perfect all of them. It didn’t help that an amateur clarinet sound is positively hideous, and practicing it came at the expense of my family’s sanity. With persistence, however, I found that I could produce incredible timbres and overtones unique to the clarinet. The rich, chocolatey texture is probably what I love most about the instrument.

I have two people to thank: my clarinet teacher, Jessica Popik, and my middle school band director, Karen Forrest. These mentors encouraged me to push my boundaries to the limit, and I wouldn’t be where I am today without them.

District and All State

I have participated in the Central District Music Festival since 7th grade and was fortunate enough to be a part of the Massachusetts All-State festival in my freshman year: one of my most memorable experiences to date. The guest conductor, Glen Adsit, was a truly charismatic person; he touched every one of the 100+ musicians in the hall with his enthusiasm and cultivated a sense of community between us. He was particularly fond of a composer friend of his, David Maslanka, the music of whom helped him develop a deeper sense of spirituality during his battle with cancer. Adsit had the opportunity to meet personally with Maslanka, and he recovered from his illness soon afterward. Our closing piece, as he informed us, was a token of gratitude and a tribute to his friend’s death.

We performed at Symphony Hall after 3 consecutive days of nonstop practice. Seeing Prof. Adsit cut off the final chord of Maslanka’s “Give Us This Day” gave me a profound feeling of exhilaration that I doubt I will ever recreate. I returned to the All-State Festival again in sophomore year, but the virtual experience was nowhere near as exciting as the real thing.



MMEA Logo

Claflin Hill

I played in the Claflin Hill Youth Wind Ensemble from 2017-2020. I was generously offered a seat on my first audition by the director, Paul Surapine, who evidently believed he could “whip me into shape”—for lack of a better term. The experience was uncharted territory for me: the expectations were high, the music was difficult, and the other musicians were several heads taller than me. Admittedly, I was quite lost for the entire first year. I struggled to play through tough passages despite practicing for hours, while the rest of my section seemingly breezed through entire pieces on the first read. The concertmaster was particularly formidable—his technique and intonation were unmatched, and he served as a role model for me.


claflin hill logo

Claflin showed me a beauty in music that I had never encountered in the cacophony known as middle school band. I used to believe that music was a procedure—a methodical practice in which playing the right notes and rhythms corresponded to checked boxes on a rubric. After joining CHYS, I practiced so that I might play like the concertmaster whom I looked up to so intently. I grew rapidly, and in my third year I rose to take the 1st chair after my idol graduated.

Machine Learning

Discovering a New World

I was first introduced to machine learning in a weeklong course over the summer of 7th grade. To be frank, it was rather poorly taught; I essentially learned to copy a computer vision program from a board with no understanding of how or why the code works (it was also written in TensorFlow 1.x. Blasphemous, right?). But the concept of making world-changing applications without needing materials or a lab was appealing to me, and harnessing that power became an obsession.

The code was written in Python, and I had a limited understanding of the language. To practice, I started making scripts to solve problems I encountered in school, searching up concepts on the Internet when I needed to expand my toolkit. Looking back at the code I wrote back then, I laugh at its naivety (it was also written in Azure Notebooks... nostalgic). But it was all part of the learning process, and every project gave me valuable experience. By the start of my freshman year, I could solve problems that I never dreamed of approaching previously.

With a newfound understanding of Python, I revisited the code I wrote years ago. Its syntax made sense to me now; it was speaking my language. However, I still didn't understand how the neural network actually 'learns'. Theoretical machine learning – the fundamental math that drives A.I algorithms – was my next pursuit. But upon glancing at the equations, I realized that I understood very little of them; they were deeply rooted in calculus and linear algebra. I never really had a passion for math, but learning these concepts was a necessary next step. I picked up just enough to re-derive each of the equations with meticulous practice and some help from the internet.

Equipped with this knowledge, I managed to build a trainable CNN from scratch, deriving all of the forward and backward-pass algorithms for gradient descent by hand. I pondered for hours on how to approach this problem, and I spent orders of magnitude more time debugging the code. The joy that I felt when the model finished training with 98% test accuracy on the MNIST dataset is indescribable.

I have a much better grasp of machine learning today than I did 4 years ago, and I smile at the progress I’ve made since then. I wouldn’t say I’m an expert; there's so much I have yet to learn. But every step I take brings my goal closer in sight.

Some of my projects can be found below, and the public code is located in Github.

# constructor and feedforward/backprop algorithms of a convolutional network I derived and implemented from scratch.

class ConvLayer(Layer):

def __init__(self, kernel_size, activation, stride=1, zero_padding='valid'):

"""kernel_size - a list of length 2 containing integers representing the x and y sizes of the filter"""

super().__init__()

self.activation = super().activations[activation]

self.kernel_size = kernel_size

self.stride = stride

self.zero_padding = zero_padding


def feedforward(self, a): # a : ndarray of R^4: (batch size, x, y, channel)

self.set_input(a)

output = np.zeros([a.shape[0]] + [int((i-k)/self.stride) + 1 for i, k in zip(a.shape[1:3], self.kernel_size)] + [a.shape[3]])

a = np.transpose(a, (1,2,0,3))

output = np.transpose(output, (1,2,0,3)) # to (image x, image y, batch size, channel) : set values in batches

for i in range(output.shape[0]):

for j in range(output.shape[1]):

output[i][j] = np.einsum("ijkl, ij -> kl", a[i*self.stride:i*self.stride+self.kernel_size[0], j*self.stride:j*self.stride+self.kernel_size[1]], self.filter)

self.z = np.transpose(output, (2,0,1,3)) + self.biases

return self.activation.fn(self.z)


def backprop(self, dconv, lr): # dconv : da/dL from layer FF.

delta = dconv * self.activation.prime(self.z) # delta is the derivative of the cost with respect to z.

dCdb = delta

dCdF = np.zeros(self.filter.shape + (delta.shape[0],)) # grad filter (filter x, filter y, batch size)

delta, a = (np.transpose(delta, (1,2,0,3)), np.transpose(self.a, (1,2,0,3))) # reshape to dimensions (x, y, batch, channel)

dCda = np.zeros(a.shape)

for i in range(delta.shape[0]):

for j in range(delta.shape[1]):

x, y = (i * self.stride, j * self.stride)

dCdF += np.sum(delta[i][j] * a[x:x+self.kernel_size[0], y:y+self.kernel_size[1]], axis=3) # a is the orginal input to the layer.

dCda[x:x+self.kernel_size[0], y:y+self.kernel_size[1]] += np.einsum("ij,kl->ijkl", self.filter, delta[i][j])

self.filter = self.filter - (lr/dCdF.shape[2])*np.sum(np.transpose(dCdF, (2,0,1)), axis=0)

self.biases = self.biases - (lr/dCdb.shape[0])*np.sum(dCdb, axis=0)

return np.transpose(dCda, (2,0,1,3))

UMass Research Group

I joined a quantum chemistry lab at UMass Amherst over the summer, headed by Professor Zhou Lin. I gained experience in data processing and graph neural networks–specifically, I used RDKit to preprocess molecular SMILES and PyTorch/pytorch_geometric to build graph processing networks. Currently, I am working on an ongoing project involving the prediction of optical properties of chromophores in solvents. In essence, this is a multi-target regression problem, but it has several intricacies. Firstly, molecules are identified by their atoms and the bonds that connect them. This data is difficult to represent in latent space, so I decided on encoding them as graphs instead (non-Euclidean data consisting of node features and an adjacency matrix). Additionally, since the solvent affects the molecule’s optical properties, there is a need to process multiple graphs simultaneously to account for the interaction between them. The project hasn’t made any progress after school started, as I couldn’t find time to work on it. However, some of the problems I encountered in the lab have inspired my research for the STEM1 project.


group photo over zoom
ubuffalo logo

University @ Buffalo Internship

I worked briefly with PhD student Shuo Qian and Professor Jun Qu on the analysis of proteomics data. During this time, I learned to use Pandas, a python library for handling matrices and spreadsheets. I still prefer to work exclusively with NumPy when dealing with matrices, but Pandas admittedly has some useful features that can’t be done in np. One of my projects was to create a binary classifier for a quantitative proteomics dataset, and I approached this problem with a rather naive approach using a fully-connected neural network, batch normalization, dropout, ReLU activations, and a sigmoidal prediction layer. However, due to the limited amount of training samples, the model was grossly overfit and doubtlessly performed worse than standard statistical analysis. This experience taught me that machine learning isn’t always the right solution to a problem; existing computational methods should always be utilized if they exist and conform to some qualifications.