From e70c10534792d04308d3bc7281c977f0b51cd393 Mon Sep 17 00:00:00 2001 From: Rushil Umaretiya Date: Wed, 11 May 2022 12:33:46 -0400 Subject: [PATCH] feat: updated to latest after course --- Unit 4/crossword/Umaretiya_r_U4_L5.py | 257 ++++++++++++++++++++++++++ Unit 5/Umaretiya_r_U5_L1.py | 116 ++++++++++++ Unit 6/Kanchinadam_n_U6_L2.py | 132 +++++++++++++ Unit 6/Umaretiya_r_U6_L1.py | 75 ++++++++ Unit 6/Umaretiya_r_U6_L2.py | 132 +++++++++++++ Unit 6/weights.txt | 3 + Unit 6/x_gate.txt | 5 + Unit 6/x_gate_2.txt | 4 + Unit 7/Kim_k_U7_L1.py | 139 ++++++++++++++ Unit 7/Umaretiya_r_U7_L1.py | 108 +++++++++++ Unit 7/cute_dog.jpg | Bin 0 -> 5084 bytes Unit 7/output.png | Bin 0 -> 53792 bytes Unit 7/turtle.jpg | Bin 0 -> 6190 bytes 13 files changed, 971 insertions(+) create mode 100644 Unit 4/crossword/Umaretiya_r_U4_L5.py create mode 100644 Unit 5/Umaretiya_r_U5_L1.py create mode 100644 Unit 6/Kanchinadam_n_U6_L2.py create mode 100644 Unit 6/Umaretiya_r_U6_L1.py create mode 100644 Unit 6/Umaretiya_r_U6_L2.py create mode 100644 Unit 6/weights.txt create mode 100644 Unit 6/x_gate.txt create mode 100644 Unit 6/x_gate_2.txt create mode 100644 Unit 7/Kim_k_U7_L1.py create mode 100644 Unit 7/Umaretiya_r_U7_L1.py create mode 100644 Unit 7/cute_dog.jpg create mode 100644 Unit 7/output.png create mode 100644 Unit 7/turtle.jpg diff --git a/Unit 4/crossword/Umaretiya_r_U4_L5.py b/Unit 4/crossword/Umaretiya_r_U4_L5.py new file mode 100644 index 0000000..cd7d56a --- /dev/null +++ b/Unit 4/crossword/Umaretiya_r_U4_L5.py @@ -0,0 +1,257 @@ +import sys; args = sys.argv[1:] + +# Name: Rushil Umaretiya +# Date: 3-18-2021 + +import re + +BLOCKCHAR = '#' +OPENCHAR = '-' +PROTECTEDCHAR = '~' + +def crossword(args): + # parse input + # args = ['13x13', '32', 'dct20k.txt', 'H1x4#Toe#', 'H9x2#', 'V3x6#', 'H10x0Scintillating', 'V0x5stirrup', 'H4x2##Ordained', 'V0x1Sums', 'V0x12Mah', 'V5x0pew'] + height, width, block_count, wordlist, words = parse_input(args) + + # initialize board + board, width, height, block_count = initialize(width, height, words, block_count) + + print("init board:") + display(board, width, height) + + # add blocking chars + print("add blocks:") + board = add_blocks(board, width, height, block_count) + + if board == None: + print('Board is none.') + raise Exception(f'Board is none.') + + # display(board, width, height) + # remove border + board, width, height = finish_board(board, width, height, words) + + #print(f'{block_count} {board.count(BLOCKCHAR)}') + print(board.count(BLOCKCHAR)) + display(board, width, height) + +def parse_input(args): + tests = [r'^(\d+)x(\d+)$', r'^\d+$', r'^(H|V)(\d+)x(\d+)(.+)$'] + height, width, block_count, wordlist, words = 0, 0, 0, '', [] + + for arg in args: + # if os.path.isfile(arg): + # wordlist = arg + # else: + for i in range(len(tests)): + match = re.search(tests[i], arg, re.I) + if match == None: continue + if i == 0: + height = int(match.group(1)) + width = int(match.group(2)) + elif i == 1: + block_count = int(match.group(0)) + elif i == 2: + words.append((match.group(1).upper(), int(match.group(2)), int(match.group(3)), match.group(4).upper())) + return height, width, block_count, wordlist, words + +def initialize(width, height, words, block_count): + board = OPENCHAR * height * width + for word in words: + index = word[1] * width + word[2] + for letter in word[3]: + new_char = BLOCKCHAR if letter == BLOCKCHAR else PROTECTEDCHAR + board = board[:index] + new_char + board[index + 1 :] + board = board[:(len(board) - 1) - index] + new_char + board[len(board) - index:] + if word[0] == 'H': + index += 1 + else: + index += width + block_count -= board.count(BLOCKCHAR) + display(board, width, height) + board = add_border(board, width, height) + width += 2 + height += 2 + # display(board, width, height) + board = protect(board, width, height) + # display(board, width, height) + return board, width, height, block_count + +def protect(board, width, height): + right_test = rf'({BLOCKCHAR}(\w|{PROTECTEDCHAR})(\w|{PROTECTEDCHAR})){OPENCHAR}' + left_test = rf'{OPENCHAR}((\w|{PROTECTEDCHAR})(\w|{PROTECTEDCHAR}){BLOCKCHAR})' + + for i in range(2): + board = re.sub(left_test, rf'{PROTECTEDCHAR}\1', board) + board = re.sub(right_test, rf'\1{PROTECTEDCHAR}', board) + board = transpose(board, width) + width, height = height, width + # display(board, width, height) + + return board + +def transpose(board, width): + return ''.join([board[col::width] for col in range(width)]) + +def add_border(board, width, height): + border_board = BLOCKCHAR*(width+3) + border_board +=(BLOCKCHAR*2).join([board[p:p+width] for p in range(0,len(board),width)]) + border_board += BLOCKCHAR*(width+3) + return border_board + +def remove_border(board, width, height): + no_border = '' + for i in range(len(board)): + if (width <= i < width * (height - 1)) and ((i + 1) % width != 0) and (i % width != 0): + no_border += board[i] + return no_border, width - 2, height - 2 + +def blocking_heuristic(index, board, width): + left = 0 + temp = index + while board[temp] != BLOCKCHAR: + left += 1 + temp += 1 + right = 0 + temp = index + while board[temp] != BLOCKCHAR: + right += 1 + temp -= 1 + up = 0 + temp = index + while board[temp] != BLOCKCHAR: + up += 1 + temp += width + down = 0 + temp = index + while board[temp] != BLOCKCHAR: + down += 1 + temp -= width + return up * down + left * right + +def add_blocks(board, width, height, block_count): + if block_count == 0: + return board + + if board.count(OPENCHAR) == block_count: + return BLOCKCHAR * len(board) + + if block_count % 2 == 1: + if width * height % 2 == 1: + board = board[: len(board) // 2] + BLOCKCHAR + board[(len(board) // 2) + 1 :] + block_count -= 1 + else: + raise Exception("Cannot place an odd number of blockchars on an even sized board.") + + print(board) + if re.search(f'#[{PROTECTEDCHAR+OPENCHAR}]{{1,2}}#', board) or re.search(f'#[{PROTECTEDCHAR+OPENCHAR}]{{1,2}}#', transpose(board, width)): + + display(board, width, height) + + for i in range(2): + presub = board.count(BLOCKCHAR) + board, num = re.subn(f'#([{PROTECTEDCHAR+OPENCHAR}][{PROTECTEDCHAR+OPENCHAR}]#)*', lambda x: '#' * len(x.group()), board) + board, num = re.subn(f'#([{PROTECTEDCHAR+OPENCHAR}]#)*', lambda x: '#' * len(x.group()), board) + block_count -= board.count(BLOCKCHAR) - presub + + board = transpose(board, width) + width, height = height, width + + # print("yes.") + display(board, width, height) + # print("yes") + possible = [i for i in range(len(board)) if board[i] != BLOCKCHAR] + fills = {} + + for i in possible: + fills[i] = area_fill(board, width, i) + + fill_counts = {} + for fill in fills.keys(): + count = fills[fill].count('?') + + if count not in fill_counts.values(): + fill_counts[fill] = count + + fill_counts = {key: value for key, value in sorted(fill_counts.items(), key=lambda item: item[1])} + for fill in fill_counts: + if fill_counts[fill] < (width - 2) * (height - 2) - (board.count(PROTECTEDCHAR) + board.count(OPENCHAR)): + board = area_fill(board, width, fill, char=BLOCKCHAR) + board = area_fill(board, width, len(board) - 1 - fill, char=BLOCKCHAR) + block_count -= fill_counts[fill] * 2 + break + + options = [i for i in range(len(board)) if board[i] == board[(len(board) - 1) - i] == OPENCHAR] + return blocks_backtrack(board, width, height, block_count, options) + +def blocks_backtrack(board, width, height, block_count, options): + # print(options) + # display(board, width, height) + + if block_count == 0 or len(options) == 0: + return board + + for option in sorted(options, key=lambda i: blocking_heuristic(i, board, width)): + if is_valid_blocking(board, width, height, option): + copy = board[:option] + BLOCKCHAR + board[option + 1 :] + copy = copy[: (len(copy) - 1) - option] + BLOCKCHAR + copy[len(copy) - option :] + updated_options = [i for i in options if i != option] + result = blocks_backtrack(copy, width, height, block_count - 2, updated_options) + if result != None: return result + + return None + +def is_valid_blocking(board, width, height, option): + if board[option] != OPENCHAR: return False + temp = board[:option] + BLOCKCHAR + board[option + 1:] + temp = temp[:(len(temp) - 1) - option] + BLOCKCHAR + temp[len(temp) - option :] + + illegalRegex = rf"[{BLOCKCHAR}](.?({PROTECTEDCHAR}|{OPENCHAR})|({PROTECTEDCHAR}|{OPENCHAR}).?)[{BLOCKCHAR}]" + if re.search(illegalRegex, temp) != None: return False + if re.search(illegalRegex, transpose(temp, width)) != None: return False + return True + +def area_fill(board, width, sp, char='?'): + dirs = [-1, width, 1, -1 * width] + if sp < 0 or sp >= len(board): return board + if board[sp] in (OPENCHAR, PROTECTEDCHAR): + board = board[0:sp] + char + board[sp+1:] + for d in dirs: + if d == -1 and sp % width == 0: continue + if d == 1 and sp + 1 % width == 0: continue + board = area_fill(board, width, sp + d, char) + return board + +def finish_board(board, width, height, words): + # remove border + board, width, height = remove_border(board, width, height) + + # add words + for word in words: + index = word[1] * width + word[2] + for letter in word[3]: + board = board[:index] + letter + board[index + 1 :] + if word[0] == 'H': + index += 1 + else: + index += width + + # replace protected with open + board = re.sub(PROTECTEDCHAR, OPENCHAR, board) + + return board, width, height + +def display(board, width, height): + for i in range(height): + line = "" + for letter in range(width): + line += (board[(i * width) + letter] + " ") + print(line) + print() + +def main(): + crossword(args) + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/Unit 5/Umaretiya_r_U5_L1.py b/Unit 5/Umaretiya_r_U5_L1.py new file mode 100644 index 0000000..d8f4e19 --- /dev/null +++ b/Unit 5/Umaretiya_r_U5_L1.py @@ -0,0 +1,116 @@ +from pomegranate import * + +# Pop Quiz + +# Graduated (G) Node +Graduated = DiscreteDistribution({'graduated':0.9, 'no-graduated':0.1}) + +# Offer Child Nodes +Offer1 = ConditionalProbabilityTable([ +['graduated', 'offer', 0.5], +['graduated', 'no-offer', 0.5], +['no-graduated', 'offer', 0.05], +['no-graduated', 'no-offer', 0.95]], [Graduated]) + +Offer2 = ConditionalProbabilityTable([ +['graduated', 'offer', 0.75], +['graduated', 'no-offer', 0.25], +['no-graduated', 'offer', 0.25], +['no-graduated', 'no-offer', 0.75]], [Graduated]) + +# Setting up states for each node +s_graduated = State(Graduated, 'graduated-offer') +s_offer_1 = State(Offer1, 'offer_1') +s_offer_2 = State(Offer2, 'offer_2') + +# Creating Bayesian Network +model = BayesianNetwork('graduated-offer') + +# Adding nodes to network +model.add_states(s_graduated, s_offer_1, s_offer_2) + +# Creating edges +model.add_transition(s_graduated, s_offer_1) +model.add_transition(s_graduated, s_offer_2) + +model.bake() # finalize the topology of the model + +print() +print('Pop Quiz:') +print('The number of nodes:', model.node_count()) +print('The number of edges:', model.edge_count()) + +# predict_proba(Given factors) +# P(o2 | g, ~o1) +print('P(o2 | g, ~o1): ', model.predict_proba({'graduated-offer': 'graduated', 'offer_1': 'no-offer'})[2].parameters[0]['offer']) + +# predict_proba(Given factors) +# P(g | o1, o2) +print('P(g | o1, o2): ', model.predict_proba({'offer_1': 'offer', 'offer_2': 'offer'})[0].parameters[0]['graduated']) + +# predict_proba(Given factors) +# P(g | ~o1, o2) +print('P(g | ~o1, o2): ', model.predict_proba({'offer_1': 'no-offer', 'offer_2': 'offer'})[0].parameters[0]['graduated']) + +# predict_proba(Given factors) +# P(g | ~o1, ~o2) +print('P(g | ~o1, ~o2): ', model.predict_proba({'offer_1': 'no-offer', 'offer_2': 'no-offer'})[0].parameters[0]['graduated']) + +# predict_proba(Given factors) +# P(o2 | o1) +print('P(o2 | o1): ', model.predict_proba({'offer_1': 'offer'})[2].parameters[0]['offer']) + +# Example 5, Day 2 Note + +# Happiness Factors +Sunny = DiscreteDistribution({'sunny':0.7, 'not-sunny':0.3}) +Raise = DiscreteDistribution({'raise': 0.01, 'no-raise': 0.99}) + +# Happiness Conditional Probability +Happiness = ConditionalProbabilityTable([ +['sunny', 'raise', 'happy', 1], +['sunny', 'raise', 'not-happy', 0], +['sunny', 'no-raise', 'happy', 0.7], +['sunny', 'no-raise', 'not-happy', 0.3], +['not-sunny', 'raise', 'happy', 0.9], +['not-sunny', 'raise', 'not-happy', 0.1], +['not-sunny', 'no-raise', 'happy', 0.1], +['not-sunny', 'no-raise', 'not-happy', 0.9]], [Sunny, Raise]) + +# Setting up states for each node +s_sunny = State(Sunny, 'is-sunny') +s_raise = State(Raise, 'got-raise') +s_happiness = State(Happiness, 'happiness') + +# Creating Bayesian Network +model = BayesianNetwork('happiness-network') + +# Adding nodes to network +model.add_states(s_sunny, s_raise, s_happiness) + +# Creating edges +model.add_transition(s_sunny, s_happiness) +model.add_transition(s_raise, s_happiness) + +model.bake() # finalize the topology of the model + +print() +print('Day 2 Note, Example 3:') +print('The number of nodes:', model.node_count()) +print('The number of edges:', model.edge_count()) + +# predict_proba(Given factors) +# P(r | s) +print('P(r | s): ', model.predict_proba({'is-sunny': 'sunny'})[1].parameters[0]['raise']) + +# predict_proba(Given factors) +# P(r | h, s) +print('P(r | h, s): ', model.predict_proba({'is-sunny': 'sunny', 'happiness': 'happy'})[1].parameters[0]['raise']) + +# predict_proba(Given factors) +# P(r | h) +print('P(r | h): ', model.predict_proba({'happiness': 'happy'})[1].parameters[0]['raise']) + +# predict_proba(Given factors) +# P(r | h, ~s) +print('P(r | h, ~s): ', model.predict_proba({'is-sunny': 'not-sunny', 'happiness': 'happy'})[1].parameters[0]['raise']) \ No newline at end of file diff --git a/Unit 6/Kanchinadam_n_U6_L2.py b/Unit 6/Kanchinadam_n_U6_L2.py new file mode 100644 index 0000000..396835b --- /dev/null +++ b/Unit 6/Kanchinadam_n_U6_L2.py @@ -0,0 +1,132 @@ +import sys; args = sys.argv[1:] +import math, random + +# Sample input: x_gate.txt + + +# t_funct is symbol of transfer functions: 'T1', 'T2', 'T3', or 'T4' +# input is a list of input (summation) values of the current layer +# returns a list of output values of the current layer +def transfer(t_funct, input): + if t_funct == 'T3': return [1 / (1 + math.e**-x) for x in input] + elif t_funct == 'T4': return [-1+2/(1+math.e**-x) for x in input] + elif t_funct == 'T2': return [x if x > 0 else 0 for x in input] + else: return [x for x in input] + +def + +# returns a list of dot_product result. the len of the list == stage +# dot_product([x1, x2, x3], [w11, w21, w31, w12, w22, w32], 2) => [x1*w11 + x2*w21 + x3*w31, x1*w12, x2*w22, x3*w32] +def dot_product(input, weights, stage): + return [sum([input[x]*weights[x+s*len(input)] for x in range(len(input))]) for s in range(stage)] + +# Complete the whole forward feeding for one input(training) set +# return updated x_vals and error of the one forward feeding +def ff(ts, xv, weights, t_funct): + + ''' ff coding goes here ''' + for i in range(len(weights) - 1): + for j in range(len(xv[i + 1])): + xv[i + 1][j] = 0 + for j in range(len(weights[i])): + xv[i + 1][j // len(xv[i])] += xv[i][j % len(xv[i])] * weights[i][j] + xv[i + 1] = transfer(t_funct, xv[i + 1]) + for i in range(len(weights[-1])): + xv[-1][i] = xv[-2][i] * weights[-1][i] + err = (ts[-1] - xv[-1][0])**2 / 2 + return xv, err + +# Complete the back propagation with one training set and corresponding x_vals and weights +# update E_vals (ev) and negative_grad, and then return those two lists +def bp(ts, xv, weights, ev, negative_grad): + + ''' bp coding goes here ''' + ev[-1][0] = ts[-1] - xv[-1][0] + for i in range(len(weights) - 1, -1, -1): + for j in range(len(negative_grad[i])): + negative_grad[i][j] = xv[i][j % len(xv[i])] * ev[i + 1][j // len(ev[i])] + if i != 0: + for j in range(len(ev[i])): + ev[i][j] = 0 + for k in range(len(ev[i + 1])): + ev[i][j] += ev[i + 1][k] * weights[i][k * len(ev[i]) + j] + ev[i][j] *= xv[i][j] * (1 - xv[i][j]) + return ev, negative_grad + +# update all weights and return the new weights +# Challenge: one line solution is possible +def update_weights(weights, negative_grad, alpha): + + ''' update weights (modify NN) code goes here ''' + for i in range(len(weights)): + for j in range(len(weights[i])): + weights[i][j] += negative_grad[i][j] * alpha + return weights + +def main(): + file = sys.argv[1] # only one input (a txt file with training set data) + #if not os.path.isfile(file): exit("Error: training set is not given") + t_funct = 'T3' # we default the transfer(activation) function as 1 / (1 + math.e**(-x)) + training_set = [[float(x) for x in line.split() if x != '=>'] for line in open(file, 'r').read().splitlines() if line.strip() != ''] + #print (training_set) #[[1.0, -1.0, 1.0], [-1.0, 1.0, 1.0], [1.0, 1.0, 1.0], [-1.0, -1.0, 1.0], [0.0, 0.0, 0.0]] + layer_counts = [len(training_set[0]), 2, 1, 1] + print ('layer counts', layer_counts) # This is the first output. [3, 2, 1, 1] with teh given x_gate.txt + + ''' build NN: x nodes and weights ''' + x_vals = [[temp[0:len(temp)-1]] for temp in training_set] # x_vals starts with first input values + #print (x_vals) # [[[1.0, -1.0]], [[-1.0, 1.0]], [[1.0, 1.0]], [[-1.0, -1.0]], [[0.0, 0.0]]] + # make the x value structure of the NN by putting bias and initial value 0s. + for i in range(len(training_set)): + for j in range(len(layer_counts)): + if j == 0: x_vals[i][j].append(1.0) + else: x_vals[i].append([0 for temp in range(layer_counts[j])]) + #print (x_vals) # [[[1.0, -1.0, 1.0], [0, 0], [0], [0]], [[-1.0, 1.0, 1.0], [0, 0], [0], [0]], ... + + # by using the layer counts, set initial weights [3, 2, 1, 1] => 3*2 + 2*1 + 1*1: Total 6, 2, and 1 weights are needed + weights = [[round(random.uniform(-2.0, 2.0), 2) for j in range(layer_counts[i]*layer_counts[i+1])] for i in range(len(layer_counts)-1)] + weights = [[1.35, -1.34, -1.66, -0.55, -0.9, -0.58, -1.0, 1.78], [-1.08, -0.7], [-0.6]] #Example 2 + # print (weights) #[[2.0274715389784507e-05, -3.9375970265443985, 2.4827119599531016, 0.00014994269071843774, -3.6634876683142332, -1.9655046461270405] + #[-3.7349985848630634, 3.5846029322774617] + #[2.98900741942973]] + + # build the structure of BP NN: E nodes and negative_gradients + E_vals = [[*i] for i in x_vals] #copy elements from x_vals, E_vals has the same structures with x_vals + negative_grad = [[*i] for i in weights] #copy elements from weights, negative gradients has the same structures with weights + errors = [10]*len(training_set) # Whenever FF is done once, error will be updated. Start with 10 (a big num) + count = 1 # count how many times you trained the network, this can be used for index calc or for decision making of 'restart' + alpha = 0.3 + + # calculate the initail error sum. After each forward feeding (# of training sets), calculate the error and store at error list + err = sum(errors) + while err >= 0.01: + weights = [[round(random.uniform(-2.0, 2.0), 2) for j in range(layer_counts[i]*layer_counts[i+1])] for i in range(len(layer_counts)-1)] + count = 0 + while err >= 0.01: + for i in range(len(x_vals)): + x_vals[i], errors[i] = ff(training_set[i], x_vals[i], weights, t_funct) + err = sum(errors) + if count >= 2000 and err > 0.05: + break + for i in range(len(E_vals)): + bp(training_set[i], x_vals[i], weights, E_vals[i], negative_grad) + update_weights(weights, negative_grad, alpha) + count += 1 + + ''' + while err is too big, reset all weights as random values and re-calculate the error sum. + + ''' + + ''' + while err does not reach to the goal and count is not too big, + update x_vals and errors by calling ff() + whenever all training sets are forward fed, + check error sum and change alpha or reset weights if it's needed + update E_vals and negative_grad by calling bp() + update weights + count++ + ''' + # print final weights of the working NN + print ('weights:') + for w in weights: print (w) +if __name__ == '__main__': main() \ No newline at end of file diff --git a/Unit 6/Umaretiya_r_U6_L1.py b/Unit 6/Umaretiya_r_U6_L1.py new file mode 100644 index 0000000..ecd7918 --- /dev/null +++ b/Unit 6/Umaretiya_r_U6_L1.py @@ -0,0 +1,75 @@ +import sys; args = sys.argv[1:] + +# Name: Rushil Umaretiya +# Date: 4-29-2021 + +import os, math + +def transfer(t_funct, input_val): + x = sum(input_val) + functions = { + 'T1': x, + 'T2': 0 if x <= 0 else x, + 'T3': 1 / (1 + math.e ** -x), + 'T4': -1 + 2/(1+math.e**-x) + } + if t_funct in functions: + return functions[t_funct] + raise Exception('That is not a valid transfer function.') + +def dot_product(input_vals, weights, layer): + return [[input_vals[weight] * weights[layer][cell_num][weight] for weight in range(len(weights[layer][cell_num]))] for cell_num in range(len(weights[layer]))] + +def evaluate(file, input_vals, t_funct): + with open(file, 'r') as weight_file: + # had to do this because ai grader is weird + raw_lines = [[float(weight) for weight in layer.split()] for layer in weight_file.read().split('\n')] + lines = [line for line in raw_lines if len(line) != 0] + + + weights = [] + + for i in range(len(lines)): + if (i == 0): + cells = len(input_vals) + else: + cells = len(weights[i - 1]) + + cell_weight = [] + + for cell in range(len(lines[i]) // cells): + weight = lines[i][cell * cells : (cell + 1) * cells] + cell_weight.append(weight) + + weights.append(cell_weight) + + layer = 0 + while (layer < len(weights) - 1): + weighted_input = dot_product(input_vals, weights, layer) + input_vals = [] + for input_val in weighted_input: + input_vals.append(transfer(t_funct, input_val)) + layer += 1 + + output = [] + + for i in range(len(weights[layer][0])): + output.append(weights[layer][0][i] * input_vals[i]) + + return output + +def main(): + args = sys.argv[1:] + file, inputs, t_funct, transfer_found = '', [], 'T1', False + for arg in args: + if os.path.isfile(arg): + file = arg + elif not transfer_found: + t_funct, transfer_found = arg, True + else: + inputs.append(float(arg)) + if len(file)==0: exit("Error: Weights file is not given") + li = (evaluate(file, inputs, t_funct)) + for x in li: + print (x, end=' ') +if __name__ == '__main__': main() \ No newline at end of file diff --git a/Unit 6/Umaretiya_r_U6_L2.py b/Unit 6/Umaretiya_r_U6_L2.py new file mode 100644 index 0000000..396835b --- /dev/null +++ b/Unit 6/Umaretiya_r_U6_L2.py @@ -0,0 +1,132 @@ +import sys; args = sys.argv[1:] +import math, random + +# Sample input: x_gate.txt + + +# t_funct is symbol of transfer functions: 'T1', 'T2', 'T3', or 'T4' +# input is a list of input (summation) values of the current layer +# returns a list of output values of the current layer +def transfer(t_funct, input): + if t_funct == 'T3': return [1 / (1 + math.e**-x) for x in input] + elif t_funct == 'T4': return [-1+2/(1+math.e**-x) for x in input] + elif t_funct == 'T2': return [x if x > 0 else 0 for x in input] + else: return [x for x in input] + +def + +# returns a list of dot_product result. the len of the list == stage +# dot_product([x1, x2, x3], [w11, w21, w31, w12, w22, w32], 2) => [x1*w11 + x2*w21 + x3*w31, x1*w12, x2*w22, x3*w32] +def dot_product(input, weights, stage): + return [sum([input[x]*weights[x+s*len(input)] for x in range(len(input))]) for s in range(stage)] + +# Complete the whole forward feeding for one input(training) set +# return updated x_vals and error of the one forward feeding +def ff(ts, xv, weights, t_funct): + + ''' ff coding goes here ''' + for i in range(len(weights) - 1): + for j in range(len(xv[i + 1])): + xv[i + 1][j] = 0 + for j in range(len(weights[i])): + xv[i + 1][j // len(xv[i])] += xv[i][j % len(xv[i])] * weights[i][j] + xv[i + 1] = transfer(t_funct, xv[i + 1]) + for i in range(len(weights[-1])): + xv[-1][i] = xv[-2][i] * weights[-1][i] + err = (ts[-1] - xv[-1][0])**2 / 2 + return xv, err + +# Complete the back propagation with one training set and corresponding x_vals and weights +# update E_vals (ev) and negative_grad, and then return those two lists +def bp(ts, xv, weights, ev, negative_grad): + + ''' bp coding goes here ''' + ev[-1][0] = ts[-1] - xv[-1][0] + for i in range(len(weights) - 1, -1, -1): + for j in range(len(negative_grad[i])): + negative_grad[i][j] = xv[i][j % len(xv[i])] * ev[i + 1][j // len(ev[i])] + if i != 0: + for j in range(len(ev[i])): + ev[i][j] = 0 + for k in range(len(ev[i + 1])): + ev[i][j] += ev[i + 1][k] * weights[i][k * len(ev[i]) + j] + ev[i][j] *= xv[i][j] * (1 - xv[i][j]) + return ev, negative_grad + +# update all weights and return the new weights +# Challenge: one line solution is possible +def update_weights(weights, negative_grad, alpha): + + ''' update weights (modify NN) code goes here ''' + for i in range(len(weights)): + for j in range(len(weights[i])): + weights[i][j] += negative_grad[i][j] * alpha + return weights + +def main(): + file = sys.argv[1] # only one input (a txt file with training set data) + #if not os.path.isfile(file): exit("Error: training set is not given") + t_funct = 'T3' # we default the transfer(activation) function as 1 / (1 + math.e**(-x)) + training_set = [[float(x) for x in line.split() if x != '=>'] for line in open(file, 'r').read().splitlines() if line.strip() != ''] + #print (training_set) #[[1.0, -1.0, 1.0], [-1.0, 1.0, 1.0], [1.0, 1.0, 1.0], [-1.0, -1.0, 1.0], [0.0, 0.0, 0.0]] + layer_counts = [len(training_set[0]), 2, 1, 1] + print ('layer counts', layer_counts) # This is the first output. [3, 2, 1, 1] with teh given x_gate.txt + + ''' build NN: x nodes and weights ''' + x_vals = [[temp[0:len(temp)-1]] for temp in training_set] # x_vals starts with first input values + #print (x_vals) # [[[1.0, -1.0]], [[-1.0, 1.0]], [[1.0, 1.0]], [[-1.0, -1.0]], [[0.0, 0.0]]] + # make the x value structure of the NN by putting bias and initial value 0s. + for i in range(len(training_set)): + for j in range(len(layer_counts)): + if j == 0: x_vals[i][j].append(1.0) + else: x_vals[i].append([0 for temp in range(layer_counts[j])]) + #print (x_vals) # [[[1.0, -1.0, 1.0], [0, 0], [0], [0]], [[-1.0, 1.0, 1.0], [0, 0], [0], [0]], ... + + # by using the layer counts, set initial weights [3, 2, 1, 1] => 3*2 + 2*1 + 1*1: Total 6, 2, and 1 weights are needed + weights = [[round(random.uniform(-2.0, 2.0), 2) for j in range(layer_counts[i]*layer_counts[i+1])] for i in range(len(layer_counts)-1)] + weights = [[1.35, -1.34, -1.66, -0.55, -0.9, -0.58, -1.0, 1.78], [-1.08, -0.7], [-0.6]] #Example 2 + # print (weights) #[[2.0274715389784507e-05, -3.9375970265443985, 2.4827119599531016, 0.00014994269071843774, -3.6634876683142332, -1.9655046461270405] + #[-3.7349985848630634, 3.5846029322774617] + #[2.98900741942973]] + + # build the structure of BP NN: E nodes and negative_gradients + E_vals = [[*i] for i in x_vals] #copy elements from x_vals, E_vals has the same structures with x_vals + negative_grad = [[*i] for i in weights] #copy elements from weights, negative gradients has the same structures with weights + errors = [10]*len(training_set) # Whenever FF is done once, error will be updated. Start with 10 (a big num) + count = 1 # count how many times you trained the network, this can be used for index calc or for decision making of 'restart' + alpha = 0.3 + + # calculate the initail error sum. After each forward feeding (# of training sets), calculate the error and store at error list + err = sum(errors) + while err >= 0.01: + weights = [[round(random.uniform(-2.0, 2.0), 2) for j in range(layer_counts[i]*layer_counts[i+1])] for i in range(len(layer_counts)-1)] + count = 0 + while err >= 0.01: + for i in range(len(x_vals)): + x_vals[i], errors[i] = ff(training_set[i], x_vals[i], weights, t_funct) + err = sum(errors) + if count >= 2000 and err > 0.05: + break + for i in range(len(E_vals)): + bp(training_set[i], x_vals[i], weights, E_vals[i], negative_grad) + update_weights(weights, negative_grad, alpha) + count += 1 + + ''' + while err is too big, reset all weights as random values and re-calculate the error sum. + + ''' + + ''' + while err does not reach to the goal and count is not too big, + update x_vals and errors by calling ff() + whenever all training sets are forward fed, + check error sum and change alpha or reset weights if it's needed + update E_vals and negative_grad by calling bp() + update weights + count++ + ''' + # print final weights of the working NN + print ('weights:') + for w in weights: print (w) +if __name__ == '__main__': main() \ No newline at end of file diff --git a/Unit 6/weights.txt b/Unit 6/weights.txt new file mode 100644 index 0000000..f8254aa --- /dev/null +++ b/Unit 6/weights.txt @@ -0,0 +1,3 @@ +5 8 2 0 1 2 2 2 3 7 5 4 4 3 2 +0 1 7 5 4 3 +0.5 -1 \ No newline at end of file diff --git a/Unit 6/x_gate.txt b/Unit 6/x_gate.txt new file mode 100644 index 0000000..488392f --- /dev/null +++ b/Unit 6/x_gate.txt @@ -0,0 +1,5 @@ +1 -1 => 1 +-1 1 => 1 +1 1 => 1 +-1 -1 => 1 +0 0 => 0 \ No newline at end of file diff --git a/Unit 6/x_gate_2.txt b/Unit 6/x_gate_2.txt new file mode 100644 index 0000000..970bcb8 --- /dev/null +++ b/Unit 6/x_gate_2.txt @@ -0,0 +1,4 @@ +0 1 => 0 +1 0 => 0 +1 1 => 1 +0 0 => 0 \ No newline at end of file diff --git a/Unit 7/Kim_k_U7_L1.py b/Unit 7/Kim_k_U7_L1.py new file mode 100644 index 0000000..3b98257 --- /dev/null +++ b/Unit 7/Kim_k_U7_L1.py @@ -0,0 +1,139 @@ +''' Test cases: +6 https://cf.geekdo-images.com/imagepage/img/5lvEWGGTqWDFmJq_MaZvVD3sPuM=/fit-in/900x600/filters:no_upscale()/pic260745.jpg +10 cute_dog.jpg +6 turtle.jpg +''' +import PIL +from PIL import Image; +import urllib.request +import io, sys, os, random + + +def choose_random_means(k, img, pix): + means = [] + for i in range(k): + x = (int)(random.uniform(0, img.size[0]-1)) + y = (int)(random.uniform(0, img.size[1]-1)) + means.append(pix[x,y]) + return means + +# goal test: no hopping +def check_move_count(mc): + for x in mc: + if x != 0: return False + return True + +# calculate distance with the current color with each mean +# return the index of means +def dist(col, means): + minIndex, dist_sum = 0, 255**2+255**2+255**2 + for i in range(len(means)): + dist_k = ((means[i][0]-col[0]) ** 2 + (means[i][1]-col[1])**2 + (means[i][2]-col[2])**2) ** 0.5 + if dist_k < dist_sum: + minIndex = i + dist_sum = dist_k + return minIndex + +def clustering(img, pix, rgb, cb, mc, means, count): + temp_pb, temp_mc, temp_m, temp_cb = [[] for x in means], [], [], [0 for x in range(len(means))] + for tup in rgb: + temp_cb[dist(tup, means)] += 1 + temp_pb[dist(tup, means)].append(tup) + + # for i in range(img.size[0]): + # for j in range(img.size[1]): + # temp_cb[dist(pix[i, j], means)] += 1 + # temp_pb[dist(pix[i, j], means)].append(pix[i, j]) + + temp_mc = [ (a-b) for a, b in zip(temp_cb, cb)] + temp_m = [] + for li in temp_pb: + sum_r, sum_g, sum_b = 0, 0, 0 + for tup in li: + sum_r += tup[0] + sum_g += tup[1] + sum_b += tup[2] + temp_m.append((sum_r / len(li), sum_g / len(li), sum_b / len(li))) + + print ('diff', count, ':', temp_mc) + return temp_cb, temp_mc, temp_m + +def update_picture(img, pix, means): + region_dict = {} + for x in means: + region_dict[x] = 0 + for i in range(img.size[0]): + for j in range(img.size[1]): + pix[i, j] = tuple((map(int, means[dist(pix[i, j], means)]))) + + return pix, region_dict + +def distinct_pix_count(img, pix): + cols = {} + max_col, max_count = pix[0, 0], 0 + for i in range(img.size[0]): + for j in range(img.size[1]): + if pix[i, j] not in cols.keys(): + cols[pix[i, j]] = 1 + else: + cols[pix[i, j]] += 1 + for col in cols.keys(): + if cols[col] > max_count: + max_col = col + max_count = cols[col] + return len(cols.keys()), max_col, max_count, cols.keys() + +def count_regions(img, region_dict, pix, means): + region_count = [0 for x in means] + visited = set() + + + return region_count + + +def main(): + k = int(sys.argv[1]) + file = sys.argv[2] + if not os.path.isfile(file): + file = io.BytesIO(urllib.request.urlopen(file).read()) + img = Image.open(file) + pix = img.load() # pix[0, 0] : (r, g, b) + rgb = [] + print ('Size:', img.size[0], 'x', img.size[1]) + print ('Pixels:', img.size[0]*img.size[1]) + d_count, m_col, m_count, rgb = distinct_pix_count(img, pix) + print ('Distinct pixel count:', d_count) + print ('Most common pixel:', m_col, '=>', m_count) + + count_buckets = [0 for x in range(k)] + move_count = [10 for x in range(k)] + means = choose_random_means(k, img, pix) + print ('random means:', means) + count = 1 + while not check_move_count(move_count): + count += 1 + count_buckets, move_count, means = clustering(img, pix, rgb, count_buckets, move_count, means, count) + if count == 2: + print ('first means:', means) + print ('starting sizes:', count_buckets) + pix, region_dict = update_picture(img, pix, means) + print ('Final sizes:', count_buckets) + print ('Final means:') + for i in range(len(means)): + print (i+1, ':', means[i], '=>', count_buckets[i]) + regions = count_regions(img, region_dict, pix, means) # num of area fills + print ('Region counts:', regions) + img.save('kmeans/2022tkim.png', 'PNG') + + + ''' + Distinct regions: + 1: # of regions of means[0] + Final regions: + 1: # of final regions of means[0] after taking care of step 3 + Save your file in the subdirectory, kmeans/userid.png + ''' + #img.show() + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/Unit 7/Umaretiya_r_U7_L1.py b/Unit 7/Umaretiya_r_U7_L1.py new file mode 100644 index 0000000..c9acf9b --- /dev/null +++ b/Unit 7/Umaretiya_r_U7_L1.py @@ -0,0 +1,108 @@ +''' Test cases: +6 https://cf.geekdo-images.com/imagepage/img/5lvEWGGTqWDFmJq_MaZvVD3sPuM=/fit-in/900x600/filters:no_upscale()/pic260745.jpg +10 cute_dog.jpg +6 turtle.jpg +''' +import PIL +from PIL import Image +import urllib.request +import io, sys, os, random + +def choose_random_means(k, img, pix): + return [pix[(int)(random.uniform(0, img.size[0]-1)),(int)(random.uniform(0, img.size[1]-1))] for i in range(k)] + +# goal test: no hopping +def check_move_count(mc): + for move in mc: + if move != 0: return False + return True + +# calculate distance with the current color with each mean +# return the index of means +def dist(col, means): + minIndex, dist_sum = 0, 255 ** 2 + 255 ** 2 + 255 ** 2 + for i in range(len(means)): + dist_k = ((means[i][0]-col[0]) ** 2 + (means[i][1]-col[1])**2 + (means[i][2]-col[2])**2) ** 0.5 + if dist_k < dist_sum: + dist_sum = dist_k + minIndex = i + return minIndex + +def clustering(img, pix, cb, mc, means, count): + temp_pb, temp_mc, temp_m = [[] for x in means], [], [] + temp_cb = [0 for x in range(len(means))] + + for tup in rgb: + temp_cb[dist(tup, means)] += 1 + temp_pb[dist(tup, means)].append(tup) + + temp_mc = [(a - b) for a, b in zip(temp_cb, cb)] + for li in temp_pb: + sum_r, sum_g, sum_b = 0, 0, 0 + for tup in li: + sum_r += tup[0] + sum_g += tup[1] + sum_b += tup[2] + temp_m.append((sum_r / len(li), sum_g / len(li), sum_b / len(li))) + print ('diff', count, ':', temp_mc) + return temp_cb, temp_mc, temp_m + +def update_picture(img, pix, means): + region_dict = {} + return pix, region_dict + +def distinct_pix_count(img, pix): + cols = {} + max_col, max_count = pix[0, 0], 0 + return len(cols.keys()), max_col, max_count + +def count_regions(img, region_dict, pix, means): + region_count = [0 for x in means] + return region_count + + +def main(): + k = int(sys.argv[1]) + file = sys.argv[2] + if not os.path.isfile(file): + file = io.BytesIO(urllib.request.urlopen(file).read()) + img = Image.open(file) + pix = img.load() # pix[0, 0] : (r, g, b) + print ('Size:', img.size[0], 'x', img.size[1]) + print ('Pixels:', img.size[0]*img.size[1]) + d_count, m_col, m_count = distinct_pix_count(img, pix) + print ('Distinct pixel count:', d_count) + print ('Most common pixel:', m_col, '=>', m_count) + + count_buckets = [0 for x in range(k)] + move_count = [10 for x in range(k)] + means = choose_random_means(k, img, pix) + print ('random means:', means) + count = 1 + while not check_move_count(move_count): + count += 1 + count_buckets, move_count, means = clustering(img, pix, count_buckets, move_count, means, count) + if count == 2: + print ('first means:', means) + print ('starting sizes:', count_buckets) + pix, region_dict = update_picture(img, pix, means) + print ('Final sizes:', count_buckets) + print ('Final means:') + for i in range(len(means)): + print (i+1, ':', means[i], '=>', count_buckets[i]) + regions = count_regions(img, region_dict, pix, means) # num of area fills + print ('Region counts:', regions) + img.save('output.png', 'PNG') + + + ''' + Distinct regions: + 1: # of regions of means[0] + Final regions: + 1: # of final regions of means[0] after taking care of step 3 + Save your file in the subdirectory, kmeans/userid.png + ''' + img.show() + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/Unit 7/cute_dog.jpg b/Unit 7/cute_dog.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4f01055a4599bd66b78e20accf866a1f1bacbdc6 GIT binary patch literal 5084 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 literal 0 HcmV?d00001 diff --git a/Unit 7/output.png b/Unit 7/output.png new file mode 100644 index 0000000000000000000000000000000000000000..e9e13d15a0969e4d832857c9907b772a122cdf8f GIT binary patch literal 53792 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