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 0000000..4f01055 Binary files /dev/null and b/Unit 7/cute_dog.jpg differ diff --git a/Unit 7/output.png b/Unit 7/output.png new file mode 100644 index 0000000..e9e13d1 Binary files /dev/null and b/Unit 7/output.png differ diff --git a/Unit 7/turtle.jpg b/Unit 7/turtle.jpg new file mode 100644 index 0000000..e798530 Binary files /dev/null and b/Unit 7/turtle.jpg differ